package com.xbongbong.pro.statistic.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.BiConstant;
import com.xbongbong.paas.constant.FieldAttrConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.constant.XbbConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasFormRefEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.AggTypeEnum;
import com.xbongbong.paas.enums.BIProductReformEnum;
import com.xbongbong.paas.enums.BiDefaultRelationEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DataFormatEnum;
import com.xbongbong.paas.enums.DateFormatEnum;
import com.xbongbong.paas.enums.DateTypeEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.EnableEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.ScreenTypeEnum;
import com.xbongbong.paas.enums.SwitchEnum;
import com.xbongbong.paas.enums.UnitEnum;
import com.xbongbong.paas.enums.WidgetTypeEnum;
import com.xbongbong.paas.enums.bi.ChartSourceEnum;
import com.xbongbong.paas.enums.clazz.AggsTypeClass;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FormExplainHelp;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasFormRefModel;
import com.xbongbong.paas.pojo.ChartDTO;
import com.xbongbong.paas.pojo.FormExplainPojo;
import com.xbongbong.paas.pojo.dto.ChartUpdateAveDTO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.helper.ReflectHelper;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.NamedThreadFactory;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.BiProWareEntity;
import com.xbongbong.pro.domain.entity.ChartCategoryEntity;
import com.xbongbong.pro.domain.entity.ChartCategorySearchEntity;
import com.xbongbong.pro.domain.entity.ChartCategoryTextEntity;
import com.xbongbong.pro.domain.entity.ChartDrillEntity;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.domain.entity.ChartFavoriteEntity;
import com.xbongbong.pro.domain.entity.DataSetEntity;
import com.xbongbong.pro.domain.entity.DataWarningEntity;
import com.xbongbong.pro.domain.entity.IndexSetEntity;
import com.xbongbong.pro.domain.entity.ext.ChartEntityEtx;
import com.xbongbong.pro.enums.AmountFlagEnum;
import com.xbongbong.pro.enums.BoardTypeEnum;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.PackageStatusEnum;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.ValueAddedTypeEnum;
import com.xbongbong.pro.enums.datacenter.datawarning.enums.DwOperationFlagEnum;
import com.xbongbong.pro.enums.errorcodes.BiErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ChartErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ImportErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.global.ChartCategoryEnum;
import com.xbongbong.pro.enums.permission.enums.ChartProPermissionAliasEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.index.pojo.IndexSetDataPojo;
import com.xbongbong.pro.service.toolbox.statistic.help.ChartPermissionHelp;
import com.xbongbong.pro.statistic.ChartDrillItemPojo;
import com.xbongbong.pro.statistic.constant.ChartCommonConstant;
import com.xbongbong.pro.statistic.constant.ChartConstant;
import com.xbongbong.pro.statistic.constant.RelatedProductConstant;
import com.xbongbong.pro.statistic.enums.AdvancedComputingFirstEnum;
import com.xbongbong.pro.statistic.enums.AdvancedComputingSecondEnum;
import com.xbongbong.pro.statistic.enums.CategoryEnum;
import com.xbongbong.pro.statistic.enums.ChartCategoryAliasEnum;
import com.xbongbong.pro.statistic.enums.ChartCategoryTypeEnum;
import com.xbongbong.pro.statistic.enums.ChartEditOpEnum;
import com.xbongbong.pro.statistic.enums.ChartLimitEnum;
import com.xbongbong.pro.statistic.enums.ChartLimitTypeEnum;
import com.xbongbong.pro.statistic.enums.ChartOperateEnum;
import com.xbongbong.pro.statistic.enums.ChartPermissionsTypeEnum;
import com.xbongbong.pro.statistic.enums.ChartPublishEnum;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.DrillFieldEnum;
import com.xbongbong.pro.statistic.enums.FieldUseLocationEnum;
import com.xbongbong.pro.statistic.enums.FilterConditionEnum;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.enums.OriginOfChartEnum;
import com.xbongbong.pro.statistic.enums.StatisticsTypeEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeEnum;
import com.xbongbong.pro.statistic.factory.ChartAnalysisFactory;
import com.xbongbong.pro.statistic.help.ChartAttrHelp;
import com.xbongbong.pro.statistic.help.ChartInitHelp;
import com.xbongbong.pro.statistic.help.ChartResultHelp;
import com.xbongbong.pro.statistic.help.CustomHelp;
import com.xbongbong.pro.statistic.help.DataSetHelp;
import com.xbongbong.pro.statistic.help.DrillHelp;
import com.xbongbong.pro.statistic.help.LinkageHelp;
import com.xbongbong.pro.statistic.manager.feign.PaasFormFeignClient;
import com.xbongbong.pro.statistic.model.BiProWareModel;
import com.xbongbong.pro.statistic.model.ChartCategoryModel;
import com.xbongbong.pro.statistic.model.ChartCategorySearchModel;
import com.xbongbong.pro.statistic.model.ChartCustomModel;
import com.xbongbong.pro.statistic.model.ChartDrillModel;
import com.xbongbong.pro.statistic.model.ChartFavoriteModel;
import com.xbongbong.pro.statistic.model.ChartLimitModel;
import com.xbongbong.pro.statistic.model.ChartModel;
import com.xbongbong.pro.statistic.model.DataWarningModel;
import com.xbongbong.pro.statistic.pojo.ChartDrillListPojo;
import com.xbongbong.pro.statistic.pojo.ChartFieldAttrPojo;
import com.xbongbong.pro.statistic.pojo.ChartInfoDwPojo;
import com.xbongbong.pro.statistic.pojo.ChartPermissionsPojo;
import com.xbongbong.pro.statistic.pojo.ChartSavePojo;
import com.xbongbong.pro.statistic.pojo.ChartSystemSavePojo;
import com.xbongbong.pro.statistic.pojo.ChartSystemValuePojo;
import com.xbongbong.pro.statistic.pojo.ConditionPojo;
import com.xbongbong.pro.statistic.pojo.DataSourcePojo;
import com.xbongbong.pro.statistic.pojo.DataWarningFieldAttrPojo;
import com.xbongbong.pro.statistic.pojo.DataWarningSavePojo;
import com.xbongbong.pro.statistic.pojo.ExplainsPojo;
import com.xbongbong.pro.statistic.pojo.LinkageListParamPojo;
import com.xbongbong.pro.statistic.pojo.LinkageListPojo;
import com.xbongbong.pro.statistic.pojo.RelatedProductDefaultRelationPojo;
import com.xbongbong.pro.statistic.pojo.SlaveSourcePojo;
import com.xbongbong.pro.statistic.pojo.WidgetSelectPojo;
import com.xbongbong.pro.statistic.pojo.dto.AttrConditionDTO;
import com.xbongbong.pro.statistic.pojo.dto.CategoryPermissionSaveDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartBaseDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartCategorySaveDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartCategoryTextUpdateBatchDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartCustomSaveDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartDeleteDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartDrillListDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartEditDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartInitDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartListDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartListDwDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartListEditDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartMirrorInstallDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartMobileFavoriteSaveDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartMobileListDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartOperateEnableDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartPublishDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartSavePositionDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartSaveStyleDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartThroughDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartValueSaveDTO;
import com.xbongbong.pro.statistic.pojo.dto.ChartValueSaveEntity;
import com.xbongbong.pro.statistic.pojo.dto.CustomChartDeleteDTO;
import com.xbongbong.pro.statistic.pojo.dto.DataSetSourceAttrDTO;
import com.xbongbong.pro.statistic.pojo.dto.DataSourceAttrDTO;
import com.xbongbong.pro.statistic.pojo.dto.DataWarningBatchDTO;
import com.xbongbong.pro.statistic.pojo.dto.FirstCategoryDTO;
import com.xbongbong.pro.statistic.pojo.dto.FormIdBusinessTypeAttrDTO;
import com.xbongbong.pro.statistic.pojo.dto.LinkageListDTO;
import com.xbongbong.pro.statistic.pojo.dto.LinkageSaveDTO;
import com.xbongbong.pro.statistic.pojo.dto.NumFormatGetDTO;
import com.xbongbong.pro.statistic.pojo.dto.NumFormatSaveDTO;
import com.xbongbong.pro.statistic.pojo.dto.SearchAttrDTO;
import com.xbongbong.pro.statistic.pojo.dto.ShowTypeDTO;
import com.xbongbong.pro.statistic.pojo.dto.SummaryAttrGetDTO;
import com.xbongbong.pro.statistic.pojo.vo.AttrConditionVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartBaseInfoVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartBaseVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartBatchSaveVo;
import com.xbongbong.pro.statistic.pojo.vo.ChartCategorySaveVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartCustomSaveVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartDataLimitVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartDeleteVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartDrillListVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartEditVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartInfoDwVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartInitVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartMirrorInstallVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartMobileFavoriteSaveVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartMobileListVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartPermissionAndRuleDTO;
import com.xbongbong.pro.statistic.pojo.vo.ChartPermissionAndRuleVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartPublishVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartSaveUuidVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartSaveVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartThroughVO;
import com.xbongbong.pro.statistic.pojo.vo.ChartTypeListVO;
import com.xbongbong.pro.statistic.pojo.vo.CustomChartDeleteVO;
import com.xbongbong.pro.statistic.pojo.vo.DataSourceAttrVO;
import com.xbongbong.pro.statistic.pojo.vo.DataSourceObjectVO;
import com.xbongbong.pro.statistic.pojo.vo.FirstCategoryVO;
import com.xbongbong.pro.statistic.pojo.vo.LinkageListVO;
import com.xbongbong.pro.statistic.pojo.vo.NumFormatGetVO;
import com.xbongbong.pro.statistic.pojo.vo.NumFormatSaveVO;
import com.xbongbong.pro.statistic.pojo.vo.NumberAttrVO;
import com.xbongbong.pro.statistic.pojo.vo.ShowTypeVO;
import com.xbongbong.pro.statistic.pojo.vo.SummaryAttrVO;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultDTO;
import com.xbongbong.pro.statistic.service.BiProWareService;
import com.xbongbong.pro.statistic.service.ChartCategoryService;
import com.xbongbong.pro.statistic.service.ChartCategoryTextService;
import com.xbongbong.pro.statistic.service.ChartLimitService;
import com.xbongbong.pro.statistic.service.ChartResultService;
import com.xbongbong.pro.statistic.service.ChartService;
import com.xbongbong.pro.statistic.service.DataWarehouseService;
import com.xbongbong.pro.statistic.service.DataWarningService;
import com.xbongbong.pro.statistic.util.ChartUtil;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ProductCategoryEntity;
import com.xbongbong.saas.domain.entity.WorkOrderFormEntity;
import com.xbongbong.saas.domain.entity.ext.WorkOrderExplainEntityExt;
import com.xbongbong.saas.domain.entity.ext.WorkOrderFormEntityExt;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.RelativeProductEnum;
import com.xbongbong.saas.enums.UserTeamEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.base.CommunicateBaseEnum;
import com.xbongbong.saas.enums.business.ChartConfigEnum;
import com.xbongbong.saas.enums.business.ContractPerformanceEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.model.IndexSetModel;
import com.xbongbong.saas.model.ProductCategoryModel;
import com.xbongbong.saas.model.WorkOrderExplainModel;
import com.xbongbong.saas.model.WorkOrderFormModel;
import com.xbongbong.saas.service.toolbox.help.PackageStatusHelp;
import com.xbongbong.saas.service.toolbox.help.UpdatePackageRedisService;
import com.xbongbong.saas.toolbox.help.BasicHelper;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.help.ProPermissionHelp;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.DepartmentModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * 图表/指标相关
 *
 * @author zcp
 * @version v1.0
 * @date 2019/1/11
 * @since v1.0
 */
@Service("chartService")
public class ChartServiceImpl implements ChartService {

    private static final Logger LOG = LoggerFactory.getLogger(ChartServiceImpl.class);
    @Resource
    private ChartModel chartModel;
    @Resource
    private ChartCustomModel chartCustomModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private ChartFavoriteModel chartFavoriteModel;
    @Resource
    private ChartCategoryModel chartCategoryModel;
    @Resource
    private ChartInitHelp chartInitHelp;
    @Resource
    private DataWarehouseService dataWarehouseService;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private IndexSetModel indexSetModel;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private CustomHelp customHelp;
    @Resource
    private WorkOrderExplainModel workOrderExplainModel;
    @Resource
    private WorkOrderFormModel workOrderFormModel;
    @Resource
    private ChartPermissionHelp chartPermissionHelp;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private PackageStatusHelp packageStatusHelp;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private BiProWareService biProWareService;
    @Resource
    private BiProWareModel biProWareModel;
    @Resource
    private ProductCategoryModel productCategoryModel;
    @Resource
    private UpdatePackageRedisService updatePackageRedisService;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private ChartResultService chartResultService;
    @Resource
    private PackageHelp packageHelp;
    @Resource
    private ChartCategorySearchModel chartCategorySearchModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private ChartCategoryService chartCategoryService;
    @Resource
    private PaasFormFeignClient paasFormFeignClient;
    @Resource
    private DataWarningService dataWarningService;
    @Resource
    private DataWarningModel dataWarningModel;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private PaasFormRefModel paasFormRefModel;
    @Resource
    private ChartLimitModel chartLimitModel;

    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private ChartCategoryTextService chartCategoryTextService;
    @Resource
    private ChartLimitService chartLimitService;
    @Resource
    private ChartDrillModel chartDrillModel;
    @Resource
    private DrillHelp drillHelp;
    @Resource
    private FormExplainHelp formExplainHelp;
    @Resource
    private ChartAttrHelp chartAttrHelp;
    @Resource
    private DataSetHelp dataSetHelp;
    @Resource
    private ChartResultHelp chartResultHelp;
    @Resource
    private LinkageHelp linkageHelp;

    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 120L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(10), new NamedThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());

    @Override
    public DataSourceAttrVO dataSourceAttr(DataSourceAttrDTO dataSourceAttrDTO) throws XbbException {
        DataSourceAttrVO dataSourceAttrVO = new DataSourceAttrVO();
        try {
            String corpid = dataSourceAttrDTO.getCorpid();
            Integer single = dataSourceAttrDTO.getSingle();
            Integer chartType = dataSourceAttrDTO.getChartType();
            JSONArray jsonArray = new JSONArray();
            JSONObject driveSource = dataSourceAttrDTO.getDriverSources();
            jsonArray.add(driveSource);
            if (Objects.equals(0, single)) {
                JSONArray slaveSources = dataSourceAttrDTO.getSlaveSources();
                if(slaveSources == null || slaveSources.isEmpty()){
                    throw  new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224014, StatisticsServicesErrorCodeEnum.API_ERROR_224014.getMsg());
                }
                String driveBusinessType = driveSource.getString("businessType");
                Long formId = driveSource.getLongValue("formId");
                PaasFormRefEntity paasFormRefEntity = new PaasFormRefEntity();
                if (BIProductReformEnum.getProductSubBusList().contains(Integer.parseInt(driveBusinessType))) {
                    paasFormRefEntity = paasFormRefModel.getMainFormIdByFormId(formId, corpid);
                }
                //默认关系数组
                List<RelatedProductDefaultRelationPojo> relatedProductDefaultRelationPojos = new ArrayList<>();
                for (int i = 0; i < slaveSources.size(); i++) {
                    RelatedProductDefaultRelationPojo relatedProductDefaultRelationPojo = new RelatedProductDefaultRelationPojo();
                    JSONObject slaveSource = slaveSources.getJSONObject(i);
                    String slaveBusinessType = slaveSource.getString("businessType");
                    String multipleCode = "";
                    if (!BIProductReformEnum.getDefineDefaultRelBus().contains(Integer.parseInt(driveBusinessType))) {
                        multipleCode = driveBusinessType + "_" + slaveBusinessType;
                    }else {
                        multipleCode = driveBusinessType + "_" + slaveBusinessType + "_" + paasFormRefEntity.getType();
                    }
                    BiDefaultRelationEnum biLinkEnum = BiDefaultRelationEnum.getByMutiCode(multipleCode);
                    if (biLinkEnum == null) {
                        multipleCode = slaveBusinessType + "_" + driveBusinessType;
                        biLinkEnum = BiDefaultRelationEnum.getByMutiCode(multipleCode);
                    }
                    if (biLinkEnum != null) {
                        JSONObject defaultRelationObj = JSONObject.parseObject(biLinkEnum.getDefaultAttr());
                        String driveAttr = defaultRelationObj.getJSONObject(driveSource.getString("businessType")).getString("attr");
                        String slaveAttr = defaultRelationObj.getJSONObject(slaveSource.getString("businessType")).getString("attr");
                        relatedProductDefaultRelationPojo.setDefaultMainAttr(driveAttr);
                        relatedProductDefaultRelationPojo.setDefaultRelatedAttr(slaveAttr);
                        if (BIProductReformEnum.getProductSubBusList().contains(Integer.parseInt(driveBusinessType))) {
                            relatedProductDefaultRelationPojo.setSubProductTag(RelatedProductConstant.SUB_PRODUCT_TAG_TRUE);
                        }else {
                            relatedProductDefaultRelationPojo.setSubProductTag(RelatedProductConstant.SUB_PRODUCT_TAG_FALSE);
                        }
                        relatedProductDefaultRelationPojos.add(relatedProductDefaultRelationPojo);
                    } else {
                        //没有默认关联关系时，赋空，保证数组index与slaveSources.size相对应
                        relatedProductDefaultRelationPojos.add(null);
                    }
                }
                dataSourceAttrVO.setDefaultRelation(relatedProductDefaultRelationPojos);
                jsonArray.addAll(slaveSources);
            }else{
                JSONArray slaveSources = dataSourceAttrDTO.getSlaveSources();
                if(slaveSources != null && slaveSources.size() > 0) {
                    jsonArray.addAll(slaveSources);
                }
            }
            List<SlaveSourcePojo> sources = JSONArray.parseArray(jsonArray.toJSONString(),SlaveSourcePojo.class);
            specialDriverSourceQueryChange(dataSourceAttrDTO, sources);
            //单表情况下 且 子数据源size > 0 表示为自定义表单关联数据字段处理
            boolean isLinkedData = dataSourceAttrDTO.getSingle() == 1 && sources.size() > 0;
            if(isLinkedData){
                SlaveSourcePojo driveSourcePojo = sources.get(0);
                List<String> names = new ArrayList<>();
                for (int i = 0; i < sources.size(); i++) {
                    SlaveSourcePojo slaveSourcePojo = sources.get(i);
                    if(i != 0){
                        List<String> linkedNames = slaveSourcePojo.getLinkedSourceName();
                        if (linkedNames != null && linkedNames.size() > 0) {
                            names.addAll(linkedNames);
                        }
                    }
                }
                driveSourcePojo.setLinkedSourceName(names);
            }
            sources.forEach(slaveSourcePojo -> {
                try {
                    if (slaveSourcePojo.getDriveLinkedAttr() == null) {
                        chartAttrHelp.setDataSourceAttrVO(dataSourceAttrVO, corpid, slaveSourcePojo, null, single, sources, chartType);
                    }
                } catch (XbbException e) {
                    LOG.error("设置待选字段数据出错", e);
                }
            });
            // 单维度多指标权限(旗舰版才有)
            Boolean isUltimate = Objects.equals(packageHelp.getFeeType(dataSourceAttrDTO.getCorpid()), PackageTypeEnum.ULTIMATE.getType());
            dataSourceAttrVO.setDataWarningPermissions(isUltimate);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paasForm数据库查询表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return dataSourceAttrVO;
    }




    @Override
    public DataSourceAttrVO dataSetSourceAttr(DataSetSourceAttrDTO dataSetSourceAttrDTO) throws XbbException {
        DataSourceAttrVO dataSourceAttrVO = new DataSourceAttrVO();
        String corpid = dataSetSourceAttrDTO.getCorpid();
        Long formId = dataSetSourceAttrDTO.getFormId();
        Integer businessType = dataSetSourceAttrDTO.getBusinessType();
        Integer saasMark = dataSetSourceAttrDTO.getSaasMark();

        String formName = "";
        Long appId = null;
        List<FieldAttrEntity> showExplainList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Integer distributorMark = DistributorMarkEnum.OTHER.getCode();
        if (Objects.equals(XbbRefTypeEnum.CONTRACT_PERFORMANCE.getCode(), businessType)) {
            //业绩分配
            for (ContractPerformanceEnum contractPerformanceEnum : ContractPerformanceEnum.values()) {
                FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
                BeanUtil.copyProperties(contractPerformanceEnum, fieldAttrEntity);
                fieldAttrEntity.setFormId(formId);
                showExplainList.add(fieldAttrEntity);
            }
            formName = XbbRefTypeEnum.CONTRACT_PERFORMANCE.getName();
        } else {
            BIProductReformEnum biProductReformEnum = BIProductReformEnum.getEnumByProductBusinessType(businessType);
            if (Objects.nonNull(biProductReformEnum)) {
                PaasFormExplainEntity paasFormExplainEntity = new PaasFormExplainEntity();
                PaasFormRefEntity paasFormRefEntity = new PaasFormRefEntity();
                // 查看表单主表信息
                PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
                if (paasFormEntityExt == null) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }
                paasFormRefEntity = paasFormRefModel.getMainFormIdByFormId(formId, corpid);
                String proudctAttr = BIProductReformEnum.getProductAttr(businessType, paasFormRefEntity.getType());
                PaasFormEntityExt mainPaasForm = paasFormModel.getByKey(paasFormRefEntity.getMainFormId(), corpid);
                paasFormExplainEntity = paasFormExplainModel.getByFormId(paasFormRefEntity.getMainFormId(), corpid);
                if (paasFormExplainEntity == null) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                }
                List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
                Map<String, Object> explainMap = explainList.stream().collect(Collectors.toMap(FieldAttrEntity::getAttr, fieldAttrEntity -> fieldAttrEntity));
                FieldAttrEntity productFieldAttrEnity = (FieldAttrEntity) explainMap.get(proudctAttr);
                SubFormPoJo subForm = productFieldAttrEnity.getSubForm();
                //因为产品名称会在下面给过滤掉，所以这边需要给产品名称表单解释重新赋值一下，以及增加一个产品编号的表单解释
                List<FieldAttrEntity> subFormList = new ArrayList<>();
                chartAttrHelp.handleSubProductFieldList(subFormList, subForm, formId, paasFormRefEntity);
                //fieldAttrEntities = subFormList;
                if (!BIProductReformEnum.getMultipleProductCodeList().contains(businessType)) {
                    formName = String.format(I18nMessageUtil.getMessage(RelatedProductConstant.PRODUCT_LINK_NAME), mainPaasForm.getName());
                }else {
                    formName = String.format(I18nMessageUtil.getMessage(RelatedProductConstant.PRODUCT_LINK_NAME_SEN), mainPaasForm.getName(), productFieldAttrEnity.getAttrName());
                }
                showExplainList = subFormList;
                //关联产品字段（下面处理了）
               /* FieldAttrEntity subProductFieldAttrEntity = new FieldAttrEntity();
                subProductFieldAttrEntity.setBusinessType(businessType);
                XbbRefTypeEnum mainProductXbbRefTypeEnum = XbbRefTypeEnum.getByCode(XbbRefTypeEnum.PRODUCT.getCode());
                subProductFieldAttrEntity.setAttr(StringUtil.getDataBaseString(biProductReformEnum.getDbFieldLinkMainBusiness()));
                subProductFieldAttrEntity.setFieldType(FieldTypeEnum.LINK_BUSINESS_SINGLE.getType());
                subProductFieldAttrEntity.setAttrName(mainProductXbbRefTypeEnum.getName() + RelatedProductConstant.ATTR_NAME_JOIN);
                showExplainList.add(subProductFieldAttrEntity);*/
                //关联主业务字段
                XbbRefTypeEnum mainXbbRefTypeEnum = XbbRefTypeEnum.getByCode(paasFormRefEntity.getMainBusinessType());
                String attrName = "";
                if (Objects.equals(mainPaasForm.getDistributorMark(), DistributorMarkEnum.DISTRIBUTOR.getCode())) {
                    //兼容经销商的场景
                    attrName = mainPaasForm.getName() + RelatedProductConstant.ATTR_NAME_JOIN;
                }else {
                    attrName = mainXbbRefTypeEnum.getName() + RelatedProductConstant.ATTR_NAME_JOIN;
                }
               
                FieldAttrEntity  dataFieldAttrEntity = new FieldAttrEntity();
                dataFieldAttrEntity.setBusinessType(businessType);
                dataFieldAttrEntity.setAttr(biProductReformEnum.getDbFieldLinkMainBusiness());
                dataFieldAttrEntity.setFieldType(FieldTypeEnum.ID.getType());
                dataFieldAttrEntity.setAttrName(attrName);
                dataFieldAttrEntity.setFormId(formId);
                showExplainList.add(dataFieldAttrEntity);
            }else{
                FormExplainPojo formExplainPojo = formExplainHelp.getFormAndExplain(corpid, businessType, formId);
                formName = formExplainPojo.getFormName();
                distributorMark = formExplainPojo.getDistributorMark();
                showExplainList = formExplainPojo.getExplainList();
                appId = formExplainPojo.getAppId();
            }
        }
        List<FieldAttrEntity> selectExplainList = new ArrayList<>((ArrayList)CloneUtil.deepClone(showExplainList));
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMapByList(showExplainList, null);
        //二次筛选-枚举类screenType判定
        selectExplainList.removeIf(explain ->
                (explain.getScreenType()!=null && explain.getScreenType() < ScreenTypeEnum.SCREEN_SEARCH.getType()) || FieldTypeEnum.selectAbleFilter(explain.getFieldType())
                        || Objects.equals(explain.getIsOpen(), 0)
        );

        boolean distributorFlag = Objects.equals(distributorMark, DistributorMarkEnum.DISTRIBUTOR.getCode());
        boolean team = Objects.equals(businessType, XbbRefTypeEnum.WAREHOUSE.getCode()) || Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode()) || Objects.equals(businessType, XbbRefTypeEnum.COMMUNICATE_PLAN.getCode());
        List<Integer> teamAttrList = FieldTypeEnum.getTeamList();
        //无团队表，主表也无协同人字段，所以移除协同人
        boolean coUserFlag = XbbRefTypeEnum.noTbUser(businessType);
        showExplainList.removeIf(explain ->
                (explain.getScreenType()!=null && explain.getScreenType() < ScreenTypeEnum.SCREEN_SHOW.getType()) || FieldTypeEnum.showAbleFilter(explain.getFieldType())
                        || Objects.equals(explain.getIsOpen(), 0)
                        || (Objects.equals(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), businessType) && distributorFlag && (Objects.equals(explain.getAttr() , "num_3") || Objects.equals(explain.getAttr(), "num_4")))
                        || (Objects.equals(XbbRefTypeEnum.DISTRIBUTOR_ACCOUNT.getCode(), businessType) && Objects.equals(explain.getFieldType(), FieldTypeEnum.CREATORID.getType()))
                        || ((Objects.equals(XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode() , businessType) || Objects.equals(XbbRefTypeEnum.DISTRIBUTOR_COMMUNICATE.getCode(), businessType)) && Objects.equals(explain.getAttr(), CommunicateBaseEnum.MEMO.getAttr()))
                        //移除仓库、产品、访客计划的ownerId、coUserId（无团队表）
                || (team && teamAttrList.contains(explain.getFieldType()))
                        //无团队表，移除协同人（负责人会使用主表的owner_id）
                || (coUserFlag && Objects.equals(FieldTypeEnum.COUSERID.getType(), explain.getFieldType()))
        );
        //包含在筛选条件内的把ScreenType置为SCREEN_SEARCH
        for (FieldAttrEntity fieldAttrEntity : showExplainList) {
           /* if(selectAttrSet.contains(fieldAttrEntity.getAttr())){
                fieldAttrEntity.setScreenType(ScreenTypeEnum.SCREEN_SEARCH.getType());
            }*/
            if (XbbRefTypeEnum.PRODUCT.getCode() == businessType.intValue() && ProductEnum.CATEGORY_ID.getAttr().equals(fieldAttrEntity.getAttr())) {
                fieldAttrEntity.setAttrType("text");
            }
        }
        //蕴藏字段
        DataSourceObjectVO hideObjectVO = new DataSourceObjectVO();
        //可展示字段，表头/穿透
        DataSourceObjectVO showDataSourceObjectVO = new DataSourceObjectVO();
        showDataSourceObjectVO.setFormId(formId);
        showDataSourceObjectVO.setName(formName);
        if(CollectionsUtil.isNotEmpty(showExplainList)){
            //统计表可汇总的
            DataSourceObjectVO querySummaryDataSourceObjectVo = new DataSourceObjectVO();
            List<Integer> noSearchIdList = FieldTypeEnum.esaliasTypeList().getNoSearchIdList();
            List<Integer> numIdList = FieldTypeEnum.esaliasTypeList().getNumIdList();
            Iterator<FieldAttrEntity> explainIt = showExplainList.iterator();
            List<String> linkedNames = new ArrayList<>();
            while (explainIt.hasNext()){
                FieldAttrEntity fieldAttrEntity = explainIt.next();
                // 字段回收站处理
                if (Objects.equals(fieldAttrEntity.getIsOpen(), 2)) {
                    continue;
                }
                fieldAttrEntity.setBusinessType(businessType);
                FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(fieldAttrEntity.getFieldType());
                //跳过工单业务的status类型字段
//                if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)
//                        && Objects.equals(fieldTypeEnum,FieldTypeEnum.WORK_ORDER_STATUS) ){
//                    continue;
//                }
                ChartFieldAttrPojo chartFieldAttrPojo = new ChartFieldAttrPojo();
                chartFieldAttrPojo.setAppId(appId);
                chartFieldAttrPojo.setSaasMark(saasMark);
                if(FieldTypeEnum.LINK_DATA.equals(fieldTypeEnum)){
                    if(!Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)){
                        chartAttrHelp.linkedDataAttrHandle(fieldAttrEntity, corpid, linkedNames, dataSourceAttrVO, null, null);
                    }
                    continue;
                }else if(FieldTypeEnum.ADDRESS.equals(fieldTypeEnum)){
                    chartFieldAttrPojo = chartAttrHelp.commonDataSourceAttrEnclosure(fieldAttrEntity, businessType, corpid, formId);
                } else if (FieldTypeEnum.isSubFormType(fieldAttrEntity.getFieldType())){
                    // 子表单处理
                    chartAttrHelp.subFormAttrHandle(fieldAttrEntity, showDataSourceObjectVO, numIdList, querySummaryDataSourceObjectVo, businessType, saasMark, appId);
                    continue;
                } else {
                    if (FieldTypeEnum.LINK_BUSINESS_SINGLE.equals(fieldTypeEnum) || FieldTypeEnum.LINK_BUSINESS_MULTI.equals(fieldTypeEnum) || FieldTypeEnum.BIRTHDAY.equals(fieldTypeEnum)) {
                        BeanUtil.copyProperties(fieldAttrEntity, chartFieldAttrPojo);
                        FieldAttrEntity linkedAttr = explainMap.get(chartFieldAttrPojo.getLinkedText());
                        if(linkedAttr !=null){
                            linkedAttr.setFormId(formId);
                            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(linkedAttr));
                            chartFieldAttrPojo.setLinkedAttr(jsonObject);
                        }
                    } else {
                        chartFieldAttrPojo = chartAttrHelp.commonDataSourceAttrEnclosure(fieldAttrEntity, businessType, corpid, formId);
                    }
                }
                Integer fieldType = chartFieldAttrPojo.getFieldType();
                if (!noSearchIdList.contains(fieldType)) {
                    if (numIdList.contains(fieldType) || Objects.equals(fieldAttrEntity.getAmountFlag(), AmountFlagEnum.YES.getType()) ) {
                        //chartFieldAttrPojo.setAttrType(fieldTypeEnum.getAlias());
                        if (Objects.isNull(chartFieldAttrPojo.getAttrType())){
                            chartFieldAttrPojo.setAttrType(fieldTypeEnum.getAlias());
                        }
                    }
                    //查询下拉选需要传saaaMark
                    chartFieldAttrPojo.setSaasMark(saasMark);
                    showDataSourceObjectVO.addFieldList(chartFieldAttrPojo);
                }
            }
            //添加ID
            FieldAttrEntity  dataFieldAttrEntity = new FieldAttrEntity();
            dataFieldAttrEntity.setBusinessType(businessType);
            dataFieldAttrEntity.setFormId(formId);
            dataFieldAttrEntity.setAttr(FieldTypeEnum.ID.getAlias());
            dataFieldAttrEntity.setFieldType(FieldTypeEnum.ID.getType());
            dataFieldAttrEntity.setAttrName("ID");
            dataFieldAttrEntity.setIsOpen(0);
            showDataSourceObjectVO.addFieldList(dataFieldAttrEntity);
            hideObjectVO.addFieldList(dataFieldAttrEntity);
            FieldAttrEntity  PNoFieldAttrEntity = new FieldAttrEntity();
            BIProductReformEnum biProductReformEnum = BIProductReformEnum.getEnumByProductBusinessType(businessType);
            if (Objects.nonNull(biProductReformEnum)) {
                //添加产品ID
                PNoFieldAttrEntity.setBusinessType(businessType);
                PNoFieldAttrEntity.setFormId(formId);
                PNoFieldAttrEntity.setAttr(RelativeProductEnum.PRODUCT_ID.getSaasAttr());
                PNoFieldAttrEntity.setFieldType(FieldTypeEnum.ID.getType());
                PNoFieldAttrEntity.setAttrName(RelativeProductEnum.PRODUCT_ID.getAttrName());
                PNoFieldAttrEntity.setIsOpen(0);
            }
            //数据集业绩分配关联ID需要显示
            if (Objects.equals(businessType,XbbRefTypeEnum.CONTRACT_PERFORMANCE.getCode())) {
                //添加合同id
                FieldAttrEntity  entityContractIdEntity = new FieldAttrEntity();
                entityContractIdEntity.setBusinessType(businessType);
                entityContractIdEntity.setFormId(formId);
                entityContractIdEntity.setAttr(ContractPerformanceEnum.CONTRACT_ID.getAttr());
                entityContractIdEntity.setFieldType(FieldTypeEnum.LINK_BUSINESS_SINGLE.getType());
                entityContractIdEntity.setAttrName(ContractPerformanceEnum.CONTRACT_ID.getAttrName());
                showDataSourceObjectVO.addFieldList(entityContractIdEntity);
            }
            showDataSourceObjectVO.addFieldList(PNoFieldAttrEntity);
        }
        //若各项数据为null
        if(CollectionsUtil.isNotEmpty(showDataSourceObjectVO.getFieldList())) {
            chartAttrHelp.changeNameWithI18n(showDataSourceObjectVO.getFieldList());
            dataSourceAttrVO.addShowAble(showDataSourceObjectVO);
        }
        //无formId的表tb_saas_contract_performance,tb_saas_specification,tb_saas_assemble_product,tb_saas_supplier_product,tb_saas_returned_purchase_product,tb_saas_quotation_product,tb_saas_bom_product,tb_saas_purchase_product,tb_saas_production_order_product,tb_saas_opportunity_product
        //添加formID,无formId的表除外
        if (isNeedFormId(businessType)) {
            FieldAttrEntity formFieldAttrEntity = new FieldAttrEntity();
            formFieldAttrEntity.setBusinessType(businessType);
            formFieldAttrEntity.setFormId(formId);
            formFieldAttrEntity.setAttr(FieldTypeEnum.FORM_ID.getAlias());
            formFieldAttrEntity.setFieldType(FieldTypeEnum.FORM_ID.getType());
            formFieldAttrEntity.setAttrName(FieldTypeEnum.FORM_ID.getDescription());
            formFieldAttrEntity.setIsOpen(0);
            hideObjectVO.addFieldList(formFieldAttrEntity);
        }
        dataSourceAttrVO.addHideAble(hideObjectVO);
        return dataSourceAttrVO;
    }
    /**
     * @author  gzt
     * @Description 无formId的表不能添加formId实体
     * @Date 16:42 2022/11/18
     * @param businessType
     * @return boolean
     * @throws
     **/

    private boolean isNeedFormId(Integer businessType) {
        return !Objects.equals(businessType, XbbRefTypeEnum.CONTRACT_PERFORMANCE.getCode())
                && !Objects.equals(businessType, XbbRefTypeEnum.ASSEMBLE_PRODUCT.getCode())
                && !Objects.equals(businessType, XbbRefTypeEnum.SUPPLIER_PRODUCT.getCode())
                && !Objects.equals(businessType, XbbRefTypeEnum.RETURNEDPURCHASE_PRODUCT.getCode())
                && !Objects.equals(businessType, XbbRefTypeEnum.QUOTATION_PRODUCT.getCode())
                && !Objects.equals(businessType, XbbRefTypeEnum.BOM_BILL_PRODUCT.getCode())
                && !Objects.equals(businessType, XbbRefTypeEnum.PURCHASE_PRODUCT.getCode())
                && !Objects.equals(businessType, XbbRefTypeEnum.PRODUCTION_ORDER_PRODUCT.getCode())
                && !Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY_PRODUCT.getCode());
    }

    @Override
    public NumberAttrVO searchNumberAttr(FormIdBusinessTypeAttrDTO formIdBusinessTypeAttrDTO) throws XbbException {
        //要返回的数据
        NumberAttrVO numberAttrVO = new NumberAttrVO();
        String corpid = formIdBusinessTypeAttrDTO.getCorpid();
        //formId和businessType 映射关系
        JSONObject formIdBusinessTypeList = formIdBusinessTypeAttrDTO.getFormIdBusinessTypeList();
        if (Objects.equals(formIdBusinessTypeAttrDTO.getSpecialField(), StringConstant.VERSION_ID)) {
            formIdBusinessTypeList.put("0", XbbRefTypeEnum.WORK_ORDER_V2_NODE_LOG_INFO.getCode());
        }
        if (!ObjectUtils.isEmpty(formIdBusinessTypeList)) {
            List<Long> formIdList = formIdBusinessTypeList.keySet().stream().map(item -> Long.valueOf(item)).collect(Collectors.toList());
            for (Long formId : formIdList) {
                //根据formId查询businessType
                Integer businessType = formIdBusinessTypeList.getInteger(String.valueOf(formId));
                BIProductReformEnum biProductReformEnum = BIProductReformEnum.getEnumByProductBusinessType(businessType);
                PaasFormExplainEntity paasFormExplainEntity = new PaasFormExplainEntity();
                List<FieldAttrEntity> fieldAttrEntities = new ArrayList<>();
                PaasFormRefEntity paasFormRefEntity = new PaasFormRefEntity();
                String formName = null;
                if (Objects.nonNull(biProductReformEnum)) {
                    // 查看表单主表信息
                    PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
                    if (paasFormEntityExt == null) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                    }
                    paasFormRefEntity = paasFormRefModel.getMainFormIdByFormId(formId, corpid);
                    String proudctAttr = BIProductReformEnum.getProductAttr(businessType, paasFormRefEntity.getType());
                    PaasFormEntityExt mainPaasForm = paasFormModel.getByKey(paasFormRefEntity.getMainFormId(), corpid);
                    paasFormExplainEntity = paasFormExplainModel.getByFormId(paasFormRefEntity.getMainFormId(), corpid);
                    if (paasFormExplainEntity == null) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                    }
                    List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
                    Map<String, Object> explainMap = explainList.stream().collect(Collectors.toMap(FieldAttrEntity::getAttr, fieldAttrEntity -> fieldAttrEntity));
                    FieldAttrEntity productFieldAttrEnity = (FieldAttrEntity) explainMap.get(proudctAttr);
                    SubFormPoJo subForm = productFieldAttrEnity.getSubForm();
                    //因为产品名称会在下面给过滤掉，所以这边需要给产品名称表单解释重新赋值一下，以及增加一个产品编号的表单解释
                    List<FieldAttrEntity> subFormList = new ArrayList<>();
                    chartAttrHelp.handleSubProductFieldList(subFormList, subForm, formId, paasFormRefEntity);
                    fieldAttrEntities = subFormList;
                    if (!BIProductReformEnum.getMultipleProductCodeList().contains(businessType)) {
                        formName = String.format(I18nMessageUtil.getMessage(RelatedProductConstant.PRODUCT_LINK_NAME), mainPaasForm.getName());
                    }else {
                        formName = String.format(I18nMessageUtil.getMessage(RelatedProductConstant.PRODUCT_LINK_NAME_SEN), mainPaasForm.getName(), productFieldAttrEnity.getAttrName());
                    }
                    /*formName = biProductEnum.getName();
                    if(Objects.equals(XbbRefTypeEnum.CONTRACT_PRODUCT.getCode(), businessType)){
                        for (ContractProductBIEnum value : ContractProductBIEnum.values()) {
                            FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
                            BeanUtil.copyProperties(value, fieldAttrEntity);
                            if (Objects.equals(fieldAttrEntity.getSaasAttr(), ProductEnum.UNIT.getSaasAttr())) {
                                String str = I18nMessageUtil.getMessage(I18nStringConstant.UNIT_LIST);
                                fieldAttrEntity.setItems(CustomHelp.setCombItem(str));
                            }
                            fieldAttrEntities.add(fieldAttrEntity);
                        }
                    }else {
                        DetailTabBusinessBIProductEnum detailTabBusinessBIProductEnum = DetailTabBusinessBIProductEnum.getByCode(biProductEnum.getParentCode(), biProductEnum.getParentCode());
                        List<RelativeProductEnum> businessProductEnumList = detailTabBusinessBIProductEnum.getList();
                        for (RelativeProductEnum relativeProductEnum : businessProductEnumList) {
                            FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
                            BeanUtil.copyProperties(relativeProductEnum, fieldAttrEntity);
                            if (Objects.equals(fieldAttrEntity.getSaasAttr(), ProductEnum.UNIT.getSaasAttr())) {
                                String str = I18nMessageUtil.getMessage(I18nStringConstant.UNIT_LIST);
                                fieldAttrEntity.setItems(CustomHelp.setCombItem(str));
                            }
                            fieldAttrEntity.setBusinessType(businessType);
                            fieldAttrEntities.add(fieldAttrEntity);
                        }
                    }
                    for (FieldAttrEntity fieldAttrEntity : fieldAttrEntities) {
                        fieldAttrEntity.setBusinessType(businessType);
                        fieldAttrEntity.setFormId(formId);
                    }*/
                } else if (Objects.equals(XbbRefTypeEnum.CONTRACT_PERFORMANCE.getCode(), businessType)) {
                    for (ContractPerformanceEnum contractPerformanceEnum : ContractPerformanceEnum.values()) {
                        FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
                        BeanUtil.copyProperties(contractPerformanceEnum, fieldAttrEntity);
                        fieldAttrEntity.setBusinessType(businessType);
                        fieldAttrEntities.add(fieldAttrEntity);
                    }
                    formName = XbbRefTypeEnum.CONTRACT_PERFORMANCE.getName();
                } else {
                    if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)) {
                        //工单
                        // 查看表单主表信息
                        WorkOrderFormEntityExt workOrderFormEntityExt = workOrderFormModel.getByKey(formId, corpid);
                        if (workOrderFormEntityExt == null) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                        }
                        formName = workOrderFormEntityExt.getName();
                        //解释表信息
                        WorkOrderExplainEntityExt workOrderExplainEntityExt = workOrderExplainModel.getByFormId(formId, corpid);
                        if (workOrderExplainEntityExt == null) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                        }
                        BeanUtil.copyProperties(workOrderExplainEntityExt, paasFormExplainEntity);
                        fieldAttrEntities = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
                    } else if(Objects.equals(XbbRefTypeEnum.WORK_ORDER_V2_NODE_LOG_INFO.getCode(), businessType)){
                        //WorkOrderV2NodeLogInfo非常规表单,走特殊逻辑
                        formName = I18nMessageUtil.getMessage(StringConstant.WORK_ORDER_V2_NODE_LOG_INFO_NAME);
                        fieldAttrEntities = JSONArray.parseArray(StringConstant.WORK_ORDER_V2_NODE_LOG_INFO_EXPLAIN, FieldAttrEntity.class);
                    } else {
                        // 查看表单主表信息
                        PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
                        if (paasFormEntityExt == null) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                        }
                        formName = paasFormEntityExt.getName();
                        //解释表信息
                        paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
                        if (paasFormExplainEntity == null) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                        }
                        fieldAttrEntities = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
                    }
                    fieldAttrEntities.forEach(entity ->{entity.setBusinessType(businessType);});
                }
                if(Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)) {
                    fieldAttrEntities.removeIf(explain -> Objects.equals(explain.getFieldType(),FieldTypeEnum.WORK_ORDER_STAGE.getType())
                            || Objects.equals(explain.getFieldType(),FieldTypeEnum.WORK_ORDER_STAGE_NAME.getType()));
                }
                fieldAttrEntities.removeIf(explain ->
                        (explain.getScreenType()!=null && explain.getScreenType() < ScreenTypeEnum.SCREEN_SHOW.getType()) || FieldTypeEnum.baseFilter(explain.getFieldType())
                                ||  !FieldTypeEnum.getComputedType().contains(explain.getFieldType())|| Objects.equals(explain.getIsOpen(), 0) || Objects.equals(explain.getIsOpen(), 2)  || Objects.equals(explain.getFieldType(), FieldTypeEnum.COMBO_LINK_BUSINESS.getType())
                );
                DataSourceObjectVO dataSourceObjectVO =new DataSourceObjectVO();
                dataSourceObjectVO.setName(formName);
                dataSourceObjectVO.setFormId(formId);
                dataSourceObjectVO.setFieldList(fieldAttrEntities);
                chartAttrHelp.groupByFieldType(dataSourceObjectVO);
                numberAttrVO.addNumberAble(dataSourceObjectVO);
            }
        }
        return numberAttrVO;
    }

    /**
     * 此方法只判断选中的限制，全公司的等晚上跑脚本
     * @param dataSourceAttrDTO
     * @return
     * @throws XbbException
     */
    @Override
    public ChartDataLimitVO chartDataLimit(DataSourceAttrDTO dataSourceAttrDTO) throws XbbException {
        ChartDataLimitVO dataSourceAttrVO = new ChartDataLimitVO();
        String corpid = dataSourceAttrDTO.getCorpid();
        JSONArray slaveSources = dataSourceAttrDTO.getSlaveSources();
        chartLimitService.chartDataLimit(corpid, dataSourceAttrDTO.getDriverSources(), slaveSources,dataSourceAttrDTO.getSingle());
        return dataSourceAttrVO;
    }


    @Override
    public DataSourceAttrVO searchSourceAttr(SearchAttrDTO searchAttrDTO) throws XbbException {
        DataSourceAttrVO dataSourceAttrVO = new DataSourceAttrVO();
        List<DataSourceAttrDTO> list = searchAttrDTO.getSourceList();
        Set<Long> menuIdSet = new HashSet<>();
        for (DataSourceAttrDTO dataSourceAttrDTO : list) {
            Integer single = dataSourceAttrDTO.getSingle();
            //驱动源
            JSONObject driverSource = dataSourceAttrDTO.getDriverSources();
            if(driverSource !=null){
                DataSourcePojo dataSourcePojo = driverSource.toJavaObject(DataSourcePojo.class);
                menuIdSet.add(dataSourcePojo.getFormId());
            }
            //从属
            if (Objects.equals(0, single)) {
                JSONArray slaveSources = dataSourceAttrDTO.getSlaveSources();
                if (slaveSources == null) {
                    continue;
                }
                for (Object slaveSource : slaveSources) {
                    JSONObject jsonObject =  new JSONObject((Map)slaveSource);
                    DataSourcePojo slaveSourcePojo = jsonObject.toJavaObject(DataSourcePojo.class);
                    if (slaveSourcePojo == null) {
                        continue;
                    }
                    menuIdSet.add(slaveSourcePojo.getFormId());
                }
            }
        }
        //此处应该是批量查询，由于分开展示的问题，暂时和单图的一起处理，后面有性能问题改成批量查询
        for (Long menuId : menuIdSet) {
//            setDataSourceAttrVO(dataSourceAttrVO, searchAttrDTO.getCorpid(), menuId);
        }
        return dataSourceAttrVO;
    }

    @Override
    public ChartBaseVO chartBaseList(ChartBaseDTO chartBaseDTO) throws XbbException {
        ChartBaseVO chartBaseVO = new ChartBaseVO();
        try {
            //默认为指标
            chartBaseDTO.setChartType(ChartTypeEnum.VALUE.getCode());
            chartBaseDTO.setDel(0);
            Long categoryId = getCateoryId4Alias(chartBaseDTO.getCorpid(), ChartCategoryAliasEnum.REPORT_BOARD.getAlias(), ChartCategoryTypeEnum.WEB_INDEX_LEFT.getCode());
            chartBaseDTO.setCategoryId(categoryId);
            Map<String, Object> map = BeanUtil.convertBean2Map(chartBaseDTO, true);
            map.put("columns", "id,icon,color,name,statistics_type,old_name,system_code");
            map.put("orderByStr", "update_time desc");
            map.remove("pageSize");
            PageHelper pageHelper = PageHelperUtil.getPageHelper(map, chartModel, chartBaseDTO.getPageSize());
            PageHelper pageCustomHelper = PageHelperUtil.getPageHelper(map, chartCustomModel, chartBaseDTO.getPageSize());
            List<ChartEntity> list = (List<ChartEntity>) PageHelperUtil.getEntityList(map, pageHelper, chartModel);
            List<ChartEntity> customList = (List<ChartEntity>) PageHelperUtil.getEntityList(map, pageCustomHelper, chartCustomModel);
            if (list == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }
            if (customList != null) {
                list.addAll(customList);
            }
            PaasAppEntity byAlias = paasAppModel.getByAlias(XbbRefTypeEnum.MARKET_MANAGEMENT.getAlias(), chartBaseDTO.getCorpid());
            Integer feeType = packageHelp.getFeeType(chartBaseDTO.getCorpid());
            boolean flag = Objects.equals(feeType, PackageTypeEnum.STANDARD.getType());
            List<ChartBaseInfoVO> chartBaseList = new ArrayList<>();
            List<String> standardSystemCode = SystemCodeEnum.getStandardSystemCode();
            for (ChartEntity chartEntity : list) {
                if (dealIsNeedToContinue(byAlias, flag, standardSystemCode, chartEntity)){
                    continue;
                }
                ChartBaseInfoVO chartBaseInfoVO = new ChartBaseInfoVO();
                BeanUtil.copyProperties(chartEntity, chartBaseInfoVO);
                chartBaseInfoVO.setChartId(chartEntity.getId());
                if(Objects.equals(StatisticsTypeEnum.SYSTEM_STATISTIC.getCode(),chartEntity.getStatisticsType())&&  StringUtil.isNotEmpty(chartEntity.getOldName()) && !Objects.equals(chartEntity.getOldName(),chartEntity.getName()) ){
                    chartBaseInfoVO.setOldName(PaasConstant.LEFT_BRACKET + chartEntity.getOldName() + PaasConstant.RIGHT_BRACKET);
                } else {
                    chartBaseInfoVO.setOldName(null);
                }
                chartBaseInfoVO.setStatisticsTypeName(StatisticsTypeEnum.getByCode(chartEntity.getStatisticsType()).getName());
                chartBaseList.add(chartBaseInfoVO);
            }
            chartBaseVO.setChartBaseList(chartBaseList);
            chartBaseVO.setPageHelper(pageHelper);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("获取指标/图表基本信息报错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return chartBaseVO;
    }

    public boolean dealIsNeedToContinue(PaasAppEntity byAlias, boolean flag, List<String> standardSystemCode, ChartEntity chartEntity) {
        return (flag && (standardSystemCode.contains(chartEntity.getSystemCode()))) || (Objects.isNull(byAlias) && standardSystemCode.contains(chartEntity.getSystemCode())
                || (Objects.nonNull(byAlias) && Objects.equals(byAlias.getEnable(), BasicConstant.ZERO) && standardSystemCode.contains(chartEntity.getSystemCode())));
    }

    @Override
    public ChartSavePojo chartList(ChartListDTO chartListDTO) throws XbbException {
        //把查询控件加入 modifiedBy:徐俊杰
        List<Integer> typeIn = chartListDTO.getChartTypeIn();
        typeIn.add(ChartTypeEnum.MULTIPLE_SEARCH.getCode());
        ChartSavePojo chartSavePojo = new ChartSavePojo();
        try {
            String corpid = chartListDTO.getCorpid();
            UserVO loginUser = chartListDTO.getLoginUser();
            //除了来自首页（发布到首页的仪表盘）外，没有图表查看权限的角色弹出，前端接收跳到首页
            Set<String> permSet = loginUser.getPermSet();
            if(!Objects.equals(chartListDTO.getOriginOfChart(), OriginOfChartEnum.HOME_PAGE.getCode())){
                if(!permSet.contains(ChartProPermissionAliasEnum.CHART_VIEW.getAlias())){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100128);
                }
            }
            // 获取套餐内数量的chartId
            List<Long> chartIdList = updatePackageRedisService.getPackageTotalChartId(corpid);
            // 获取套餐下的功能
            List<String> featureList = packageHelp.getFeatureList(corpid);
            Boolean isAdmin = loginUser.isAdmin();
            Integer num = updatePackageRedisService.getUnusedNumPackageLimit(corpid, ValueAddedTypeEnum.CUSTOM_CHART_NUM);
            Map<String, Object> map = BeanUtil.convertBean2Map(chartListDTO, true);
            List<ChartEntity> list = (List<ChartEntity>) BasicHelper.findEntitysByImitatePage(map, chartCustomModel, BasicConstant.THREE_HUNDRED);
            List<Long> idList = list.stream().map(ChartEntity::getId).collect(Collectors.toList());
            //只有自定义图表有钻取设置
            List<ChartDrillEntity> drillList = chartDrillModel.findByChartId(corpid, StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), idList);
            Map<Long, JSONArray> allChartDrillMap = null;
            if (CollectionsUtil.isNotEmpty(drillList)) {
                //自定义图表id - 层级信息数组
                allChartDrillMap = drillList.stream().collect(Collectors.toMap(ChartDrillEntity::getChartId, ChartDrillEntity::getDrill));
            }
            list.addAll(chartModel.findEntitys(map));
            List<ChartEntityEtx> listExt = new ArrayList<>();
            //全局权限控制 (新建，编辑，删除)
            JSONObject overAllPermissions = customHelp.chartOverallPermissions(chartListDTO);
            JSONObject obj = new JSONObject();
            //编辑的权限 只在全局设定不细化到单个图表
            obj.put(ChartProPermissionAliasEnum.CHART_UPDATE.getAlias(), overAllPermissions.get(ChartProPermissionAliasEnum.CHART_UPDATE.getAlias()));
            //ck、旗舰版、且有钻取权限，则有钻取开关
            boolean chartDrill = customHelp.drillPermission(corpid, permSet);
            obj.put(ProPermissionAliasEnum.CHART_DRILL.getAlias(), chartDrill);
            chartSavePojo.setChartPermissions(obj);
            // 获取部门
            Map<Long, List<Long>> subDepIdMap = departmentModel.getSubDepIdMap(chartListDTO.getCorpid(), false);
            Set<Long> depIdIn = CustomHelp.getSubDepIds(loginUser.getDepSet(), subDepIdMap);
            // 获取分类
            ChartCategoryEntity chartCategoryEntity = chartCategoryModel.getByKey(chartListDTO.getCategoryId(), chartListDTO.getCorpid());
            if (null == chartCategoryEntity || chartCategoryEntity.getDel() == 1) {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224084, StatisticsServicesErrorCodeEnum.API_ERROR_224084.getMsg());
            }
            for (ChartEntity chartEntity : list) {
                //可见权限控制
                JSONObject permissionsJson = chartEntity.getPermissions();
                // 自定义pk的特殊处理：自定义pk的permissions从category中获取
                if (Objects.isNull(permissionsJson) && Objects.equals(chartEntity.getChartType(),ChartTypeEnum.PK_CUSTOM.getCode())){
                    permissionsJson = chartCategoryEntity.getPermissions();
                }
                Map<String, Boolean> permissions = customHelp.isChartPermissions(permissionsJson,chartListDTO,overAllPermissions, subDepIdMap);
                if(!permissions.get(ChartProPermissionAliasEnum.CHART_VIEW.getAlias())){
                    continue;
                }

                //全局搜索
                if(Objects.equals(chartEntity.getChartType(),ChartTypeEnum.MULTIPLE_SEARCH.getCode())){
                    JSONArray search = chartEntity.getSearch();
                    BeanUtil.copyProperties(chartEntity,chartSavePojo);
                    chartSavePojo.setChartId(chartEntity.getId());
                    if (search != null && !search.isEmpty()) {
                        chartSavePojo.setHasSearch(1);
                        chartSavePojo.setSearch(search);
                    }
                    continue;
                }
                //处理无法发布到首页的图表
                String systemCode = chartEntity.getSystemCode();
                Integer chartType = chartEntity.getChartType();
                if (commonHelp.publishFilter(systemCode, chartType) || !permissions.get(ChartProPermissionAliasEnum.CHART_PUBLISH.getAlias())) {
                    chartEntity.setPublish(ChartPublishEnum.CANNOT_PUBLISH.getCode());
                }
                //将chartEntity转换成chartEntityEtx
                ChartEntityEtx chartEntityEtx = getChartEntityEtx(chartEntity);
                Integer numFormat = chartEntity.getNumFormat();

                if (!StringUtil.isEmpty(systemCode)) {
                    SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(systemCode);
                    // 系统图表处理
                    if(Objects.equals(systemCode, SystemCodeEnum.OPPORTUNITY_FUNNEL_CHART.getSystemCode())){
                        chartEntityEtx.setMemo(I18nMessageUtil.getMessage(StringConstant.OPPORTUNITY_FUNNEL_CHART_MEMO));
                    } else if (Objects.equals(systemCode, SystemCodeEnum.CUSTOMER_FUNNEL_CHART.getSystemCode())) {
                        chartEntityEtx.setMemo(I18nMessageUtil.getMessage(StringConstant.CUSTOMER_FUNNEL_CHART_MEMO));
                    }
                    // 数值格式显隐
                    if (Objects.equals(systemCodeEnum.getHasAmount(), 1)) {
                        chartEntityEtx.setIsAmount(1);
                        // 选了数值格式，就按数值格式的单位
                        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
                        String unit = numFormatEnum.getUnit();
                        chartEntityEtx.setUnit(unit);
                    }
                } else {
                    if (Objects.equals(chartType, ChartTypeEnum.PK_CUSTOM.getCode())) {
                        // 自定义pk通过统计值中的amountFlag来判断
                        JSONObject sourceAttrObj = chartEntityEtx.getSourceAttr();
                        Integer amountFlag = FastJsonHelper.getIntegerOrDefault(sourceAttrObj, "amountFlag", 0);
                        chartEntityEtx.setIsAmount(amountFlag);
                        // 单位转换
                        if (Objects.equals(chartEntity.getUnit(), UnitEnum.MONEY.getAlias()) && numFormat != null) {
                            // 数值格式单位转换，只有当选择"元"并且选了数值格式的时候才需要
                            NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
                            String unit = numFormatEnum.getUnit();
                            chartEntityEtx.setUnit(unit);
                        } else {
                            // 自定义单位转换,英文不支持单位
                            if (Objects.equals(LocaleContextHolder.getLocale().getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE)) {
                                chartEntityEtx.setUnit("");
                            } else {
                                String unit = customHelp.setUnit(chartEntity);
                                chartEntityEtx.setUnit(unit);
                            }
                        }
                    }
                    // 带有同环比的图表排序设置的汇总字段添加同环比的具体名称
                    handleYearChain4SortName(chartType, chartEntityEtx);
                    if (Objects.equals(chartType, ChartTypeEnum.CUSTOMER_PERFORMANCE.getCode())) {
                        // 自定义目标管理可以设置数值格式
                        chartEntityEtx.setIsAmount(1);
                    }
                    // 控制联动设置入口的显隐
                    dealLinkageDisplay(chartEntityEtx,loginUser);
                    // 处理钻取匹配信息
                    dealDrillMatchInfo(chartDrill, allChartDrillMap, chartEntityEtx);
                    //组装联动相关数据供下游使用
                    LinkageListParamPojo listParamPojo = new LinkageListParamPojo(new ArrayList<>(list),chartEntity,overAllPermissions,subDepIdMap,chartListDTO);
                    //自定义图表处理一下图表交互按钮集合（历史数据explains内无图表交互配置，需要处理默认值）
                    dealWithExplains(chartEntityEtx, chartType,listParamPojo);
                }

                //导出权限控制
                if(permissions.get(ChartProPermissionAliasEnum.CHART_EXPORT.getAlias())){
                    chartEntityEtx.setIsExport(ChartPermissionsTypeEnum.IS_ABLE.getType());
                }else{
                    chartEntityEtx.setIsExport(ChartPermissionsTypeEnum.NOT_IS_ABLE.getType());
                }
                // 自定义pk导出权限从分类中获取
                if (Objects.equals(chartEntity.getChartType(), ChartTypeEnum.PK_CUSTOM.getCode())) {
                    isExport4PkCustom(chartListDTO, chartEntityEtx, depIdIn, chartCategoryEntity);
                }

                if (StatisticsTypeEnum.SYSTEM_STATISTIC.getCode() == chartEntity.getStatisticsType()) {
                    //设置是否是图和表的字段 modifiedBy:徐俊杰
                    setIfChartAndTable(chartEntityEtx);
                    setChartSearch(chartEntityEtx);
                } else if (Objects.equals(ChartTypeEnum.PK_CUSTOM.getCode(), chartEntity.getChartType())) {
                    // 自定义pk特殊处理
                    JSONArray search = new JSONArray();
                    // 默认置入这两个筛选
                    search.add(FilterConditionEnum.TIME_ALL.getCode());
                    search.add(FilterConditionEnum.ORGANIZATION_ALL.getCode());
                    chartEntityEtx.setSearch(search);
                    //设置hasSearch属性
                    chartEntityEtx.setHasSearch(ChartConstant.HAS_SEARCH);
                }
                // 公司套餐限制
                packageHelp.companyPackageVerify(isAdmin,chartEntityEtx,chartIdList,num,featureList);
                // 数值格式塞默认值
                if (Objects.isNull(chartEntityEtx.getNumFormat())) {
                    chartEntityEtx.setNumFormat(NumFormatEnum.DEFAULT.getCode());
                }
                mapAndFunnelExplains(chartEntity,chartEntityEtx);
                listExt.add(chartEntityEtx);
            }
            chartSavePojo.setChartList(listExt);
            //查询仪表盘全局样式
            chartSavePojo.setGlobalStyleOption(chartCategoryEntity.getGlobalStyleOption());
        } catch (XbbException e) {
            throw e;
        }catch (Exception e){
            LOG.error("图表数据库查询报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return chartSavePojo;
    }

    /**
     * 控制联动设置入口的显隐
     *
     * @param chartEntityEtx 图表实体
     * @param loginUser 登陆用户信息
     * @author zyy
     * @date 2022/11/30
     * @version v1.0
     */
    private void dealLinkageDisplay(ChartEntityEtx chartEntityEtx, UserVO loginUser) throws XbbException {
        boolean lingkageFlag = linkageHelp.linkageFlag(chartEntityEtx.getCorpid(),chartEntityEtx.getChartType(),chartEntityEtx.getStatisticsType(),loginUser.getPermSet());
        if(lingkageFlag){
            chartEntityEtx.setLinkageFlag(Boolean.TRUE);
        }
    }

    /**
     * 钻取匹配规则
     *
     * @param chartDrillFlag   该图是否能钻取（非ck、非旗舰版、无钻取权限都无法钻取）
     * @param allChartDrillMap 统计图的钻取信息
     * @param chartEntityEtx   统计图扩展信息
     */
    private void dealDrillMatchInfo(boolean chartDrillFlag, Map<Long, JSONArray> allChartDrillMap, ChartEntityEtx chartEntityEtx) {
        boolean nonDrill = !chartDrillFlag || !Objects.equals(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), chartEntityEtx.getStatisticsType()) || Objects.isNull(allChartDrillMap);
        if (nonDrill) {
            return;
        }
        // 当前图表的钻取信息
        JSONArray drill = allChartDrillMap.get(chartEntityEtx.getId());
        if (CollectionsUtil.isEmpty(drill)) {
            return;
        }
        List<ChartDrillItemPojo> allDrillList = JsonHelperUtil.parseArray(JSON.toJSONString(drill), ChartDrillItemPojo.class);

        // 所有需要钻取的信息
        List<ChartDrillItemPojo> allNeedDrillList = new ArrayList<>();

        List<DrillFieldEnum> drillFieldEnumList = DrillFieldEnum.getByChartType(chartEntityEtx.getChartType());
        if (CollectionsUtil.isEmpty(drillFieldEnumList)) {
            return;
        }
        List<FieldAttrPojo> chartFieldAttrPojoList;
        for (DrillFieldEnum drillFieldEnum : drillFieldEnumList) {
            String drillField = drillFieldEnum.getAlias();
            // 图表的han
            Object value = ReflectHelper.valueGet(chartEntityEtx, drillField);
            chartFieldAttrPojoList = JsonHelperUtil.parseArray(JSON.toJSONString(value), FieldAttrPojo.class);
            if (CollectionsUtil.isEmpty(chartFieldAttrPojoList)) {
                continue;
            }
            boolean chartClassifyFlag = Objects.equals(drillField, DrillFieldEnum.CHART_CLASSIFY.getAlias());
            for (ChartDrillItemPojo drillItemPojo : allDrillList) {
                List<FieldAttrPojo> drillFieldList = drillItemPojo.getField();
                if (CollectionsUtil.isEmpty(drillFieldList)) {
                    continue;
                }
                for (int i = 0; i < drillFieldList.size(); i++) {
                    FieldAttrPojo drillFieldAttrPojo = drillFieldList.get(i);
                    for (FieldAttrPojo fieldAttrPojo : chartFieldAttrPojoList) {
                        if (drillHelp.drillMatchRule(drillFieldAttrPojo, fieldAttrPojo)) {
                            //如果drillFieldEnumList有多个，则肯定要么是 分类和系列，要么是行列分组。而当分类、系列都匹配到时，根据优先级只保留分类的钻取，因此如果匹配到钻取字段切drillField为分类字段时把系列(如果有)移除并直接返回分类。其他系列、行、列的正常封装塞入allNeedDrillList即可
                            if (chartClassifyFlag) {
                                drillItemPojo.setDrillField(DrillFieldEnum.CHART_CLASSIFY.getAlias());
                                drillItemPojo.setDrillIndex(i);
                                allNeedDrillList.clear();
                                allNeedDrillList.add(drillItemPojo);
                                JSONArray chartDrill = JsonHelperUtil.parseObject(JSON.toJSONString(allNeedDrillList), JSONArray.class);
                                chartEntityEtx.setDrill(chartDrill);
                                return;
                            }
                            drillItemPojo.setDrillField(drillField);
                            drillItemPojo.setDrillIndex(i);
                            allNeedDrillList.add(drillItemPojo);
                        }
                    }
                }
            }
            JSONArray chartDrill = JsonHelperUtil.parseObject(JSON.toJSONString(allNeedDrillList), JSONArray.class);
            chartEntityEtx.setDrill(chartDrill);
        }
    }

    /**
     * 同环比的图表 排序设置的汇总字段 添加 同环比的具体名称
     * @param chartType 图表类型
     * @param chartEntityEtx 图表实体
     * @author 梅伟丁
     * @date 2022/5/17 16:36:54
     * @version 1.0
     */
    private void handleYearChain4SortName(Integer chartType, ChartEntityEtx chartEntityEtx) {
        // 目前只有数据统计表、柱形图、折线图、双轴图排序支持同环比 (若增加，请在ChartTypeEnum.getChartType4YearChainSortName()增加)
        if (ChartTypeEnum.getChartType4YearChainSortName().contains(chartType)){
            if (CollectionUtils.isNotEmpty(chartEntityEtx.getSummaryAttr())){
                // 汇总字段
                chartEntityEtx.setSummaryAttr(handleYearChainDetail4SortName(chartEntityEtx.getSummaryAttr()));
            }
            if (CollectionUtils.isNotEmpty(chartEntityEtx.getChartValue())){
                // 值
                chartEntityEtx.setChartValue(handleYearChainDetail4SortName(chartEntityEtx.getChartValue()));
            }
            if (CollectionUtils.isNotEmpty(chartEntityEtx.getChartValueSecond())){
                // 双轴图右侧统计值
                chartEntityEtx.setChartValueSecond(handleYearChainDetail4SortName(chartEntityEtx.getChartValueSecond()));
            }
        }
    }

    /**
     * 处理具体同环比LabelName
     * @param jsonArray 字段列表
     * @return 处理后的字段列表
     * @author 梅伟丁
     * @date 2022/5/17 17:29:17
     * @version 1.0
     */
    private JSONArray handleYearChainDetail4SortName(JSONArray jsonArray) {
        try {
            for (Object obj : jsonArray) {
                JSONObject jsonObject = obj instanceof JSONObject ? (JSONObject) obj : new JSONObject();
                JSONArray advancedComputing = jsonObject.getJSONArray("advancedComputing");
                if (CollectionUtils.isNotEmpty(advancedComputing) && Objects.equals(advancedComputing.get(0), AdvancedComputingFirstEnum.YEAR_CHAIN.getAlias())){
                    if (Objects.nonNull(advancedComputing.get(1))){
                        // 在字段后拼接具体设置的同环比名称
                        if (Objects.nonNull(jsonObject.get(StringConstant.LABEL_NAME))){
                            String yearChainLabelName = AdvancedComputingSecondEnum.getNameByAlias(advancedComputing.getString(1));
                            jsonObject.put(StringConstant.LABEL_NAME_SORT,jsonObject.get(StringConstant.LABEL_NAME) + StringConstant.LEFT_BRACKETS + yearChainLabelName + StringConstant.RIGHT_BRACKETS);
                        }
                    }
                }
            }
        }catch (Exception e){
            LOG.error("LabelName设置同环比名称异常");
            return jsonArray;
        }
        return jsonArray;
    }

    @Override
    public ChartSavePojo chartListByCategory(ChartListDTO chartListDTO) throws XbbException {
        Long categoryId = chartListDTO.getCategoryId();
        String nameLike = chartListDTO.getNameLike();
        if (Objects.isNull(categoryId) && StringUtil.isEmpty(nameLike)) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224081);
        }
        String corpid = chartListDTO.getCorpid();
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.CORPID, corpid);
        param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
        List<Integer> chartTypeIn = ChartTypeEnum.getChartTypeIn4Web();
        chartTypeIn.add(ChartTypeEnum.MULTIPLE_SEARCH.getCode());
        param.put("chartTypeIn", chartTypeIn);
        if (Objects.nonNull(categoryId)) {
            param.put("categoryId", categoryId);
        }
        if (StringUtil.isNotEmpty(nameLike)) {
            param.put("nameLike", nameLike);
        }
        List<ChartEntity> chartResults = chartModel.findEntitys(param);
        chartResults.addAll(chartCustomModel.findEntitys(param));
        ChartSavePojo chartSavePojo = new ChartSavePojo();
        List<ChartEntityEtx> listExt = new ArrayList<>();
        if (CollectionUtils.isEmpty(chartResults)) {
            return chartSavePojo;
        }
        JSONObject overAllPermissions = customHelp.chartOverallPermissions(chartListDTO);
        Map<Long, List<Long>> subAllDepIdMap = departmentModel.getSubDepIdMap(corpid, false);
        //设置图表编辑页的操作按钮
        List<ChartEditOpEnum> baseOpList = ChartEditOpEnum.getBaseOpList(null);
        List<Long> customId = new ArrayList<>();
        chartResults.forEach(chartEntity -> {
            //可见权限控制
            Map<String, Boolean> permissions = customHelp.isChartPermissions(chartEntity.getPermissions(), chartListDTO, overAllPermissions, subAllDepIdMap);
            if(!permissions.get(ChartProPermissionAliasEnum.CHART_VIEW.getAlias())){
                return;
            }
            //处理无法发布到首页的图表
            String systemCode = chartEntity.getSystemCode();
            Integer chartType = chartEntity.getChartType();
            if (commonHelp.publishFilter(systemCode, chartType) || !permissions.get(ChartProPermissionAliasEnum.CHART_PUBLISH.getAlias())) {
                chartEntity.setPublish(ChartPublishEnum.CANNOT_PUBLISH.getCode());
            }
            // 自定义图表特殊处理
            if (StatisticsTypeEnum.CUSTOM_STATISTIC.getCode() == chartEntity.getStatisticsType()) {
                if (ChartTypeEnum.supportDrillChartType().contains(chartType)) {
                    customId.add(chartEntity.getId());
                }
                // 自定义单位转换,英文不支持单位
                if (Objects.equals(LocaleContextHolder.getLocale().getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE)) {
                    chartEntity.setUnit("");
                } else {
                    String unit = customHelp.setUnit(chartEntity);
                    chartEntity.setUnit(unit);
                }
            }
            //将chartEntity转换成chartEntityEtx
            ChartEntityEtx chartEntityEtx = getChartEntityEtx(chartEntity);
            // 销售漏斗备注特殊处理
            if (!StringUtil.isEmpty(systemCode)) {
                if(Objects.equals(systemCode, SystemCodeEnum.OPPORTUNITY_FUNNEL_CHART.getCode())){
                    chartEntityEtx.setMemo(I18nMessageUtil.getMessage(StringConstant.OPPORTUNITY_FUNNEL_CHART_MEMO));
                }
            }
            //打印权限控制
            if(permissions.get(ChartProPermissionAliasEnum.CHART_EXPORT.getAlias())){
                chartEntityEtx.setIsExport(ChartPermissionsTypeEnum.IS_ABLE.getType());
            }else{
                chartEntityEtx.setIsExport(ChartPermissionsTypeEnum.NOT_IS_ABLE.getType());
            }
            if (StatisticsTypeEnum.SYSTEM_STATISTIC.getCode() == chartEntity.getStatisticsType()) {
                //设置是否是图和表的字段 modifiedBy:徐俊杰
                setIfChartAndTable(chartEntityEtx);
                setChartSearch(chartEntityEtx);
            }

            // 过滤掉不能作被复制的图表
            if (!SystemCodeEnum.getCanNotSelectChart().contains(systemCode)) {
                listExt.add(chartEntityEtx);
            }
        });
        //处理图表的操作按钮,内部有查库操作，因此移动到循环外
        dealChartOpEdit(corpid,listExt);
        // 处理钻取层级信息，防止引用图表的时候丢失钻取层级信息
        if (CollectionsUtil.isNotEmpty(customId)) {
            List<ChartDrillEntity> chartDrillEntityList = chartDrillModel.findByChartId(corpid, StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), customId);
            for (ChartEntityEtx chartEntityEtx : listExt) {
                for (ChartDrillEntity chartDrillEntity : chartDrillEntityList) {
                    if (Objects.equals(chartDrillEntity.getChartId(), chartEntityEtx.getId())) {
                        chartEntityEtx.setDrill(chartDrillEntity.getDrill());
                        chartDrillEntityList.remove(chartDrillEntity);
                        break;
                    }
                }
            }
        }

        chartSavePojo.setChartList(listExt);
        return chartSavePojo;
    }

    /**
     * 获取自定义pk是否能导出
     * @param chartListDTO
     * @param chartEntityEtx
     * @param depIdIn 子部门ID以及自身所属部门ID集合
     * @param chartCategoryEntity
     * @author xinpeng.jiang
     * @date 2021/10/26 15:14
     * @version 1.0
     */
    private void isExport4PkCustom(ChartListDTO chartListDTO, ChartEntityEtx chartEntityEtx, Set<Long> depIdIn, ChartCategoryEntity chartCategoryEntity) {
        boolean customPkExportFlag = false;
        // 获取分类权限
        JSONObject categoryPermissions = chartCategoryEntity.getPermissions();
        if (Objects.isNull(categoryPermissions)) {
            chartEntityEtx.setIsExport(ChartPermissionsTypeEnum.NOT_IS_ABLE.getType());
            return;
        }
        ChartPermissionsPojo chartPermissionsPojo = JSON.parseObject(categoryPermissions.toJSONString(), ChartPermissionsPojo.class);
        // 鉴权
        customPkExportFlag = customHelp.getExportPermission(chartListDTO, customPkExportFlag, chartPermissionsPojo, depIdIn);
        // 赋值
        if (customPkExportFlag) {
            chartEntityEtx.setIsExport(ChartPermissionsTypeEnum.IS_ABLE.getType());
        } else {
            chartEntityEtx.setIsExport(ChartPermissionsTypeEnum.NOT_IS_ABLE.getType());
        }
    }

    @Override
    public ChartBatchSaveVo chartSave(ChartSavePojo chartSavePojo) throws XbbException, IllegalAccessException, InstantiationException {
        ChartBatchSaveVo chartBatchSaveVo = new ChartBatchSaveVo();
        List <ChartSaveUuidVO> chartSaveUuidList = new ArrayList<>();
        List<ChartEntity> insertList = new ArrayList<>();
        List<ChartEntity> updateList = new ArrayList<>();
        List<Long> updateIdList = new ArrayList<>();
        Map<Long,ChartEntity> chartEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        long now = DateUtil.getInt();
        Long categoryId = chartSavePojo.getCategoryId();
        // 数据预警ChartEntityEtx
        ChartEntityEtx dwChartEntityEtx = null;
        Integer feeType = packageHelp.getFeeType(chartSavePojo.getCorpid());
        // 处理全局的搜索条件TODO 产品改寻求暂时不做
//        globalSearch(chartSavePojo, insertList, updateList, now, categoryId);
        //处理报表
        List<ChartEntityEtx> etxList = chartSavePojo.getChartList();
        if (etxList != null) {
            // 查出现有的次仪表盘下的chartId集合
            HashMap<String,Object> chartParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            chartParam.put("corpid",chartSavePojo.getCorpid());
            chartParam.put("del",DelEnum.NORMAL);
            chartParam.put("categoryId",chartSavePojo.getCategoryId());
            chartParam.put("columns","id");
            List<ChartEntity> customList = chartCustomModel.findEntitys(chartParam);
            List<ChartEntity> systemList = chartModel.findEntitys(chartParam);
            List<Long> chartIds;
            if (CollectionUtils.isNotEmpty(customList)){
                chartIds = customList.stream().map(e ->e.getId()).collect(Collectors.toList());
            }else {
                chartIds = new ArrayList<>();
            }
            if (CollectionUtils.isNotEmpty(systemList)){
                chartIds.addAll(systemList.stream().map(e ->e.getId()).collect(Collectors.toList()));
            }
            //数量控制
            // 判断该公司是否在图表限制表里面
            Integer limitNum = commonHelp.getChartLimit(chartSavePojo.getCorpid(),ChartLimitTypeEnum.CHART_NUM_LIMIT.getAlias());
            //TODO 应该判断del
            if (etxList.size() > limitNum) {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224080, StatisticsServicesErrorCodeEnum.API_ERROR_224080.getMsg(), limitNum);
            }
            //高级图表类型校验
            if(!Objects.equals(PackageTypeEnum.ULTIMATE.getType(), feeType)){
                List<ChartTypeEnum> chartEtxEnums = etxList.stream().map(value -> ChartTypeEnum.getByCode(value.getChartType())).collect(Collectors.toList());
                if(!Collections.disjoint(ChartTypeEnum.getSeniorChartList(),chartEtxEnums)){
                    throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224088);
                }
            }
            //key：chart的uuid，value：该chart的drill集合
            Map<String, JSONArray> uuidDrillMap = new HashMap<>(etxList.size());
            List<Long> updateChartIdIn = new ArrayList<>();
            for (ChartEntityEtx chartEntityEtx : etxList) {
                specialDriverSourceSaveChange(chartEntityEtx);
                JSONArray rowGroupAttrArr = chartEntityEtx.getRowGroupAttr();
                JSONArray colGroupAttrArr = chartEntityEtx.getColGroupAttr();
                List<FieldAttrPojo> fieldAttrPojoList;
                Long id = chartEntityEtx.getId();
                boolean delFlag = Objects.equals(chartEntityEtx.getDel(), DelEnum.DELETE.getDel());
                if (delFlag){
                    if (CollectionUtils.isNotEmpty(chartIds) && null != id){
                        chartIds.remove(chartEntityEtx.getId());
                    }
                }else {
                    if (null != id && !chartIds.contains(id)){
                        chartIds.add(id);
                    }
                }
                boolean dataSetFlag = Objects.equals(ChartSourceEnum.DATESET.getCode(), chartEntityEtx.getSingle());
                if (Objects.equals(chartEntityEtx.getChartType(), ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())) {
                    // 统计表中必须设置行或列分组字段
                    boolean flag = Objects.equals(chartEntityEtx.getDel(), DelEnum.NORMAL.getDel()) && (CollectionUtils.isEmpty(rowGroupAttrArr) && CollectionUtils.isEmpty(colGroupAttrArr));
                    if (flag) {
                        throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224068);
                    }
                    fieldAttrPojoList = JSONArray.parseArray(chartEntityEtx.getSummaryAttr().toJSONString(), FieldAttrPojo.class);
                    // 校验相同字段
                    if (CollectionsUtil.isNotEmpty(fieldAttrPojoList) && fieldAttrPojoList.size() > 1) {
                        for (int i = 0; i < fieldAttrPojoList.size() - 1; i++) {
                            FieldAttrPojo fieldAttrPojo = fieldAttrPojoList.get(i);
                            Long formId = fieldAttrPojo.getFormId();
                            String aggType = fieldAttrPojo.getAggType();
                            JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
                            String labelName = fieldAttrPojo.getLabelName();
                            // 多表处理
                            String attr;
                            if(delFlag){
                                attr = fieldAttrPojo.getAttr();
                            }else {
                                attr = fieldAttrPojo.getOriginalAttr() == null ? fieldAttrPojo.getAttr() : fieldAttrPojo.getOriginalAttr();
                            }
                            // 检验
                            verifySimpleField(fieldAttrPojoList, i, attr, aggType, advancedComputing, labelName, formId,dataSetFlag);
                        }
                    }
                    // 校验高级条件
                    verifyAdvancedComputing(chartEntityEtx, fieldAttrPojoList, rowGroupAttrArr, colGroupAttrArr);
                } else {
                    fieldAttrPojoList = JSONArray.parseArray(chartEntityEtx.getChartValue().toJSONString(), FieldAttrPojo.class);
                    // 校验高级条件
                    verifyAdvancedComputing(chartEntityEtx, fieldAttrPojoList, rowGroupAttrArr, colGroupAttrArr);
                }
                // 如果chartEntityEtx里面的dataWarningList不为空，说明在图表中心新建或编辑的时候同时操作了数据预警，只能是单个图表操作
                if ( Objects.nonNull(chartEntityEtx.getDataWarningList()) && chartEntityEtx.getDataWarningList().size()>0){
                    dwChartEntityEtx = chartEntityEtx;
                }
                // 如果chartEntityEtx是双轴图或者单维度多精度并且用户不是旗舰版，不能保存
                Boolean isSingleDimension = CollectionUtils.isNotEmpty(chartEntityEtx.getChartValue()) && chartEntityEtx.getChartValue().size()>1;
                if (!Objects.equals(feeType,PackageTypeEnum.ULTIMATE.getType()) && (Objects.equals(chartEntityEtx.getChartType(),ChartTypeEnum.BIAXIAL_CHART.getCode()) || isSingleDimension)){
                    throw new XbbException(ChartErrorCodeEnum.API_ERROR_1500005);
                }
                // 保存
                ChartEntity entity = new ChartEntity();
                entity.setCategoryId2Category(categoryId);
                entity.setCorpid(chartSavePojo.getCorpid());
                entity.setCreatorId(chartSavePojo.getUserId());
                entity.setStatisticsType(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode());
                BeanUtil.copyProperties(chartEntityEtx, entity);
                JSONArray filterList = entity.getFilter();
                JSONArray jsonArray = new JSONArray();
                //遍历筛选条件filter
                setFilter(entity, filterList, jsonArray);
                //图表内部的验证
                ChartUtil.validateLimit(entity);
                //展示类型
                JSONArray showTypeArray = new JSONArray();
                ChartTypeEnum  chartTypeEnum = ChartTypeEnum.getByCode(entity.getChartType());
                if(chartTypeEnum == null){
                    throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224015);
                }
                List<AggsTypeClass> chartTypeEnums = ChartTypeEnum.getByTeam(chartTypeEnum.getTeam());
                for (AggsTypeClass typeClass : chartTypeEnums) {
                     showTypeArray.add(typeClass.getCode());
                }
                entity.setShowTypes(showTypeArray);
                //TODO 控件内部的验证要做
                JSONObject driver = entity.getDriverSources();
                SlaveSourcePojo driverSource = driver.toJavaObject(SlaveSourcePojo.class);
                //判断关联数据的情况
                boolean linkedOrMultiFlag = false;
                //多表的muti=0
                if(CollectionsUtil.isNotEmpty(entity.getSlaveSources())){
                    entity.setMuti(0);
                    linkedOrMultiFlag = true;
                   /* if(Objects.equals(driverSource.getBusinessType(),XbbRefTypeEnum.CONTRACT_PRODUCT.getCode())){
                        driver.put("linkFormId",entity.getSlaveSources().getJSONObject(0).getLong("formId"));
                        entity.setDriverSources(driver);
                    }*/
                }else{
                    //统计表+图+单表里有团队
                    if(ChartTypeEnum.getGroupChartType().contains(entity.getChartType()) && UserTeamEnum.hasTeam(driverSource.getBusinessType())){
                        JSONArray rowGroupAttr = entity.getRowGroupAttr();
                        JSONArray colGroupAttr = entity.getColGroupAttr();
                        JSONArray chartClassifyArray = entity.getChartClassify();
                        JSONArray chartSeriesArray = entity.getChartSeries();
                        if(CollectionsUtil.isNotEmpty(rowGroupAttr)){
                            linkedOrMultiFlag = isLinkedOrMultiFlag(entity, linkedOrMultiFlag, rowGroupAttr);
                        }
                        if(!linkedOrMultiFlag && CollectionsUtil.isNotEmpty(colGroupAttr)){
                            linkedOrMultiFlag = isLinkedOrMultiFlag(entity, linkedOrMultiFlag, colGroupAttr);
                        }
                        if(!linkedOrMultiFlag && CollectionsUtil.isNotEmpty(chartClassifyArray)){
                            linkedOrMultiFlag = isLinkedOrMultiFlag(entity, linkedOrMultiFlag, chartClassifyArray);
                        }
                        if(!linkedOrMultiFlag && CollectionsUtil.isNotEmpty(chartSeriesArray)){
                            linkedOrMultiFlag = isLinkedOrMultiFlag(entity, linkedOrMultiFlag, chartSeriesArray);
                        }
                    }
                }
                //explains中的扩展信息
                JSONObject explains = entity.getExplains();
                if(explains == null){
                    throw  new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224016);
                }
                explains = JSONObject.parseObject(explains.toJSONString());
                ExplainsPojo explainsPojo = explains.toJavaObject(ExplainsPojo.class);
                explainsPojo.setFrozeColumDone(chartEntityEtx.getFrozeColumDone());
                explainsPojo.setFrozeColum(chartEntityEtx.getFrozeColum());
                explainsPojo.setFrozeRowDone(chartEntityEtx.getFrozeRowDone());
                explainsPojo.setMap(chartEntityEtx.getMap());
                explainsPojo.setFunnel(chartEntityEtx.getFunnel());
                explainsPojo.setMapDistrict(chartEntityEtx.getMapDistrict());
                entity.setExplains(JSONObject.parseObject(JSONObject.toJSON(explainsPojo).toString()));
                Long chartId = chartEntityEtx.getId();
                boolean editAble = chartId != null && chartId > 0;
                //设置copy字段
                if(!dataSetFlag){
                    setCopyAttr(entity, editAble);
                }
                JSONArray drill = entity.getDrill();
                String uuid = chartEntityEtx.getUuid();
                Integer statisticsType = entity.getStatisticsType();
                /*
                  只有自定义指标才可能有钻取配置
                  当无层级的时候传入的drill是空数组，当无层级字段时传入的drill内field为空-无层级字段也允许生成层级
                 */
                if (Objects.equals(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), statisticsType) && Objects.nonNull(drill)) {
                    //drill非空才校验
                    if (CollectionsUtil.isNotEmpty(drill)) {
                        //单表时，把映射的字段attr回置为原始attr（上文主表chartEntity字段映射返回后已经重置muti字段）
                        if(EsUtil.getSingle(entity) && !dataSetFlag){
                            customHelp.backAttr(entity, drill);
                        }
                        List<ChartDrillItemPojo> drillList = JsonHelperUtil.parseArray(JSON.toJSONString(drill), ChartDrillItemPojo.class);
                        // 校验drill与图表的分类/系列/行列分组
                        validDrillLevelRule(drillList, entity);
                    }
                    uuidDrillMap.put(uuid, drill);
                    if (editAble) {
                        updateChartIdIn.add(chartId);
                    }
                }
                //编辑
                if (editAble) {
                    entity.setId(chartId);
                    updateList.add(entity);
                    //当是多表 且  满足
                    if (linkedOrMultiFlag) {
                        updateIdList.add(chartId);
                        chartEntityMap.put(chartId,entity);
                    }
                    // 编辑的时候把统计的缓存给清除
                    paasRedisHelper.removeValue(RedisPrefixConstant.INDEX_CUSTOM_STATISTIC_RESULT, entity.getCorpid() + "_" + entity.getId());
                } else {
                    //新建
                    entity.setEnable(1);
                    entity.setPublish(0);
                    entity.setAddTime(now);
                    entity.setChartLinkage(null);
                    insertList.add(entity);
                }
            }
            //图表新增直接设置dataSourceTime字段值
            chartInitHelp.dataSetCompareTime(Boolean.FALSE,insertList,now);
            //图表编辑时需要判断是dataSourceTime字段值
            chartInitHelp.dataSetCompareTime(Boolean.TRUE,updateList,now);

            //TODO 套餐判断 后续需要更改 假如获取到status为true, 此时若插入图表的数量超出限制则用户创建的图表数量会超出限制。 达到限制后，需要限制每天新增删除图表的次数
            //套餐判断
            int count = insertList.size();
            if (count > 0) {
                Integer status = packageStatusHelp.getPackageStatus(chartSavePojo.getCorpid(), ValueAddedTypeEnum.CUSTOM_CHART_NUM, count);
                if(!Objects.equals(status, PackageStatusEnum.NORMAL.getCode())){
                    //BI图表严格控制图表使用量，不接收少量超出
                    throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224031);
                }
            }
            // 单个仪表盘的数量限制
            int totalSize = chartIds.size() + insertList.size();
            if (totalSize > limitNum) {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224080, StatisticsServicesErrorCodeEnum.API_ERROR_224080.getMsg(), limitNum);
            }
            //TODO 应该判断del
            if (etxList.size() > limitNum) {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224080, StatisticsServicesErrorCodeEnum.API_ERROR_224080.getMsg(), limitNum);
            }
            //更换了关联字段也要触发数据源
            Map<Long,ChartEntity> chartEntityOldMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long>  initIdList = updateInitData(chartSavePojo, updateIdList, chartEntityMap,chartEntityOldMap);
            for (ChartEntity chartEntity : updateList) {
                if(!Objects.equals(ChartSourceEnum.DATESET.getCode(),chartEntity.getSingle())){
                    if(EsUtil.getSingle(chartEntity)){
                        chartEntity.setFormIdAttr(new JSONObject());
                        chartEntity.setSelectedAttr(new JSONObject());
                        chartEntity.setMuti(1);
                        customHelp.backAttr(chartEntity);
                    }else {
                        if(!chartEntityOldMap.isEmpty()){
                            chartEntity.setSelectedAttr(chartEntityOldMap.get(chartEntity.getId()).getSelectedAttr());
                        }
                    }
                    if(initIdList.contains(chartEntity.getId())){
                        customHelp.setSourcePojo(chartEntity);
                    }else {
                        //字段没有增减，只是前端交换位置或者重新置回来，更新一下相关的字段attr和originalAttr
                        customHelp.setSourcePojo(chartEntity,false);
                    }
                }
                chartCustomModel.update(chartEntity);
                String userName = chartSavePojo.getLoginUserName();
                // 记录日志
                String logMemoUpdateTemplate;
                OperateTypeEnum operateTypeEnum;
                if(chartEntity.getDel() == 1){
                    logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_DELETE_CHART);
                    operateTypeEnum = OperateTypeEnum.DELETE;
                }else if(chartEntity.getDel() == 0){
                    logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_UPDATE_CHART);
                    operateTypeEnum = OperateTypeEnum.EDIT;
                }else{
                    logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_DELETE_CHART);
                    operateTypeEnum = OperateTypeEnum.DELETE;
                }
                String memo = String.format(logMemoUpdateTemplate, userName ,chartEntity.getName());
                mongoLogHelp.buildLog(chartSavePojo.getCorpid(), chartSavePojo.getUserId(), userName, OperateModuleTypeEnum.CHART, operateTypeEnum, chartEntity.getId().toString(), chartEntity.getName(), memo, chartSavePojo.getHttpHeader());
                //
                if(initIdList.contains(chartEntity.getId())){
                    initData(chartSavePojo, chartEntity);
                }
                ChartSaveUuidVO chartSaveUuidVO = new ChartSaveUuidVO();
                BeanUtil.copyProperties(chartEntity,chartSaveUuidVO);
                chartSaveUuidList.add(chartSaveUuidVO);
            }
            if (!insertList.isEmpty()) {
                //TODO 后面要改成异步
                //处理关联表的建仓
                for (ChartEntity chartEntity : insertList) {
                    customHelp.setSourcePojo(chartEntity);
                    //复制时只给当前操作人
                    chartEntity.setCategoryId2Category(categoryId);
                    //避免由多表转为单表时，字段映射有误;  详细场景见 bug 54833
                    if (!Objects.equals(chartEntity.getMuti(),0) && !Objects.equals(ChartSourceEnum.DATESET.getCode(),chartEntity.getSingle())) {
                        customHelp.backAttr(chartEntity);
                    }
                }
                chartCustomModel.insertBatch(insertList);
                BeanUtil.copyPropertiesList(insertList,chartSaveUuidList,ChartSaveUuidVO.class);
                for (ChartEntity chartEntity : insertList) {
                    String userName = chartSavePojo.getLoginUserName();
                    // 处理数据预警
                    if (Objects.nonNull(dwChartEntityEtx)){
                        dwChartEntityEtx.setId(chartEntity.getId());
                    }
                    // 记录日志
                    String logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_ADD_CHART);
                    OperateTypeEnum operateTypeEnum = OperateTypeEnum.NEW;
                    String memo = String.format(logMemoUpdateTemplate, userName ,chartEntity.getName());
                    mongoLogHelp.buildLog(chartSavePojo.getCorpid(), chartSavePojo.getUserId(), userName, OperateModuleTypeEnum.CHART, operateTypeEnum, chartEntity.getId().toString(), chartEntity.getName(), memo, chartSavePojo.getHttpHeader());
                    //多表的关联
                    if(Objects.equals(chartEntity.getMuti(),0)){
                        initData(chartSavePojo, chartEntity);
                    }
                }
            }
            //处理图表层级设置
            dealWithDrill(chartSavePojo, uuidDrillMap, insertList, updateList, updateChartIdIn);
            chartBatchSaveVo.setChartList(chartSaveUuidList);
            // 批量添加数据预警
            List<DataWarningSavePojo> insertOrUpdateList = new ArrayList<>();
            List<DataWarningSavePojo> dwList;
            if (Objects.nonNull(dwChartEntityEtx) && Objects.nonNull(dwList = dwValue(dwChartEntityEtx))){
                insertOrUpdateList.addAll(dwList);
                if (insertOrUpdateList.size()>0){
                    dataWarningService.batchAddOrUpdate(new DataWarningBatchDTO(){{
                        setCorpid(chartSavePojo.getCorpid());
                        setUserId(chartSavePojo.getUserId());
                        setPlatform(chartSavePojo.getPlatform());
                        setHttpHeader(chartSavePojo.getHttpHeader());
                        setLoginUser(chartSavePojo.getLoginUser());
                        setLoginUserName(chartSavePojo.getLoginUserName());
                        setDataWarningSavePojoList(insertOrUpdateList);
                    }});
                }
            }
        }
        String key = chartSavePojo.getCorpid() + "_"+ ValueAddedTypeEnum.CUSTOM_CHART_NUM.getType();
        paasRedisHelper.removeValue(RedisPrefixConstant.VALUE_ADDED, key);
        return chartBatchSaveVo;
    }

    /**
     * 校验drill与图表的分类/系列/行列分组的层级规则
     *
     * @param drill       钻取字段
     * @param chartEntity 图表字段
     * @throws XbbException 销帮帮设定的异常
     */
    private void validDrillLevelRule(List<ChartDrillItemPojo> drill, ChartEntity chartEntity) throws XbbException {
        int drillSize = drill.size();
        if (drillSize > BasicConstant.FIVE) {
            throw new XbbException(BiErrorCodeEnum.API_ERROR_241030.getCode(), BiErrorCodeEnum.API_ERROR_241030.getMsg(), BasicConstant.FIVE);
        }
        List<DrillFieldEnum> drillFieldEnumList = DrillFieldEnum.getByChartType(chartEntity.getChartType());
        if (CollectionsUtil.isEmpty(drillFieldEnumList)) {
            return;
        }
        JSONArray chart;
        List<ChartFieldAttrPojo> chartFieldAttrPojoList = new ArrayList<>();
        for (DrillFieldEnum drillFieldEnum : drillFieldEnumList) {
            String drillField = drillFieldEnum.getAlias();
            // 图表的han
            Object value = ReflectHelper.valueGet(chartEntity, drillField);
            chart = Objects.nonNull(value) ? (JSONArray) value : null;
            List<ChartFieldAttrPojo> chartTempList = Objects.nonNull(chart) ? JsonHelperUtil.parseArray(JSON.toJSONString(chart), ChartFieldAttrPojo.class) : null;
            if (CollectionsUtil.isNotEmpty(chartTempList)) {
                chartFieldAttrPojoList.addAll(chartTempList);
            }
        }
        for (ChartDrillItemPojo chartDrillItemPojo : drill) {
            // 层级内字段属性
            List<FieldAttrPojo> field = chartDrillItemPojo.getField();
            if (CollectionsUtil.isEmpty(field)) {
                continue;
            }
            int fieldSize = field.size();
            if (fieldSize > BasicConstant.TEN) {
                throw new XbbException(BiErrorCodeEnum.API_ERROR_241031.getCode(), BiErrorCodeEnum.API_ERROR_241031.getMsg(), BasicConstant.TEN);
            }
            int chartCount = 0;
            // 校验同一层级内字段最多只能同时出现在某个分组内1次
            for (FieldAttrPojo drillChartFieldAttrPojo : field) {
                for (ChartFieldAttrPojo chartFieldAttrPojo : chartFieldAttrPojoList) {
                    // 校验同一层级内字段最多只能同时出现在某个分组内1次
                    chartCount = levelValidCount(drillChartFieldAttrPojo, chartFieldAttrPojo, chartCount);
                }
            }
            if (chartCount >= 2) {
                throw new XbbException(BiErrorCodeEnum.API_ERROR_241026.getCode(), BiErrorCodeEnum.API_ERROR_241026.getMsg());
            }
        }

    }

    /**
     * 检验当前层级出现在行列分组、分类、系列的次数
     *
     * @param drillChartFieldAttrPojo 钻取属性字段
     * @param chartFieldAttrPojo      当前表格属性字段（行列分组、分类、系列）
     * @param count                   出现的次数
     * @return 出现次数
     */
    private int levelValidCount(FieldAttrPojo drillChartFieldAttrPojo, ChartFieldAttrPojo chartFieldAttrPojo, int count) {
        return drillHelp.drillMatchRule(drillChartFieldAttrPojo, chartFieldAttrPojo) ? count + 1 : count;
    }

    /**
     * 重复字段校验(attr、aggType、advancedComputing、formId四者相同视为同一字段)
     * @param fieldAttrPojoList
     * @param index
     * @param attr
     * @param aggType
     * @param advancedComputing
     * @param labelName
     * @param formId
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/8/12 14:00
     * @version 1.0
     */
    private void verifySimpleField(List<FieldAttrPojo> fieldAttrPojoList, int index, String attr, String aggType, JSONArray advancedComputing, String labelName, Long formId,boolean dataSetFlag) throws XbbException {
        if (index < fieldAttrPojoList.size() - 1) {
            FieldAttrPojo fieldAttrPojo = fieldAttrPojoList.get(++index);
            Long nextFormId = fieldAttrPojo.getFormId();
            // 多表处理
            String nextAttr;
            if(dataSetFlag){
                nextAttr = fieldAttrPojo.getAttr();
            }else {
                nextAttr = fieldAttrPojo.getOriginalAttr() == null ? fieldAttrPojo.getAttr() : fieldAttrPojo.getOriginalAttr();
            }
            // sum前端会传null，处理一下
            String nextAggType = fieldAttrPojo.getAggType();
            if (Objects.isNull(aggType)) {
                aggType = AggTypeEnum.SUM.getAlias();
            }
            if (Objects.isNull(nextAggType)) {
                nextAggType = AggTypeEnum.SUM.getAlias();
            }
            // 高级计算前端也会传null
            JSONArray nextAdvancedComputing = fieldAttrPojo.getAdvancedComputing();
            if (Objects.isNull(advancedComputing)) {
                advancedComputing = new JSONArray();
                advancedComputing.add(AdvancedComputingFirstEnum.NONE.getAlias());
            }
            if (Objects.isNull(nextAdvancedComputing)) {
                nextAdvancedComputing = new JSONArray();
                nextAdvancedComputing.add(AdvancedComputingFirstEnum.NONE.getAlias());
            }
            // 校验
            if (Objects.equals(attr, nextAttr)
                    && Objects.equals(aggType, nextAggType)
                    && Objects.equals(formId, nextFormId)
                    && Objects.equals(advancedComputing, nextAdvancedComputing)) {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224075.getCode(), StatisticsServicesErrorCodeEnum.API_ERROR_224075.getMsg(), fieldAttrPojo.getLabelName(), labelName);
            }
            verifySimpleField(fieldAttrPojoList, index, attr, aggType, advancedComputing, labelName, formId,dataSetFlag);
        }
    }

    private List<DataWarningSavePojo>  dwValue(ChartEntityEtx chartEntityEtx) throws XbbException {
        if (Objects.nonNull(chartEntityEtx.getDataWarningList())){
            List<DataWarningSavePojo> pojoList = JSONObject.parseArray(chartEntityEtx.getDataWarningList().toJSONString(),DataWarningSavePojo.class);
            List<DataWarningEntity> dataWarningEntityList = dataWarningModel.findEntitys(new HashMap<String, Object>(PaasConstant.DEFAULT_INITIAL_CAPACITY){{
                put("del",DelEnum.NORMAL.getDel());
                put("corpid",chartEntityEtx.getCorpid());
                put("chartId",chartEntityEtx.getId());
                put("columns","id,enable");
            }});
            List<Long> dwIds = new ArrayList<>();
            List<Long> enableIds = new ArrayList<>();
            Integer count = 0;
            Integer enableNum = 0;
            for (DataWarningEntity item : dataWarningEntityList) {
                dwIds.add(item.getId());
                count ++;
                if (Objects.equals(item.getEnable(),BasicConstant.IS_USE)){
                    enableNum ++;
                    enableIds.add(item.getId());
                }
            }
            for (DataWarningSavePojo pojo : pojoList) {
                //防止图表也是创建的，此时前端没有在dataWarningList传chartId
                pojo.setChartId(chartEntityEtx.getId());

                if (!Objects.equals(pojo.getOperationFlag(), DwOperationFlagEnum.DEL.getCode()) && !dwIds.contains(pojo.getId())){
                    count ++;
                }

                if (Objects.equals(pojo.getOperationFlag(), DwOperationFlagEnum.DEL.getCode()) && dwIds.contains(pojo.getId())){
                    count --;
                }

                if (!Objects.equals(pojo.getOperationFlag(), DwOperationFlagEnum.DEL.getCode()) && Objects.equals(pojo.getEnable(),BasicConstant.IS_USE) && !enableIds.contains(pojo.getId())){
                    enableNum ++;
                }

                if (!Objects.equals(pojo.getOperationFlag(), DwOperationFlagEnum.DEL.getCode()) && Objects.equals(pojo.getEnable(),BasicConstant.NO_USE) && enableIds.contains(pojo.getId())){
                    enableNum --;
                }

                if (Objects.equals(pojo.getOperationFlag(), DwOperationFlagEnum.DEL.getCode()) && enableIds.contains(pojo.getId())){
                    enableNum --;
                }

            }
            try {
                if (count > PaasConstant.DATA_WARNING_MAX_CREATE_NUM){
                    throw new XbbException(ChartErrorCodeEnum.API_ERROR_1500001, String.format(ChartErrorCodeEnum.API_ERROR_1500001.getMsg(),PaasConstant.DATA_WARNING_MAX_CREATE_NUM));
                }
                if (enableNum > PaasConstant.DATA_WARNING_MAX_ENABLE_NUM){
                    throw new XbbException(ChartErrorCodeEnum.API_ERROR_1500004, String.format(ChartErrorCodeEnum.API_ERROR_1500004.getMsg(),PaasConstant.DATA_WARNING_MAX_ENABLE_NUM));
                }
            } catch (XbbException e) {
                throw  e;
            }
            return pojoList;
        }
        return null;
    }

    /**
     * 校验高级条件
     * @param chartEntityEtx
     * @param fieldAttrPojoList 汇总字段集合
     * @param rowGroupAttrArr 行分组字段
     * @param colGroupAttrArr 列分组字段
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/6/7 13:58
     * @version 1.0
     */
    private void verifyAdvancedComputing(ChartEntityEtx chartEntityEtx, List<FieldAttrPojo> fieldAttrPojoList, JSONArray rowGroupAttrArr, JSONArray colGroupAttrArr) throws XbbException {
        try {
            JSONArray chartClassify = chartEntityEtx.getChartClassify();
            JSONArray chartSeries = chartEntityEtx.getChartSeries();
            int rowDateNum = verifyDate(rowGroupAttrArr);
            int colDateNum = verifyDate(colGroupAttrArr);
            int seriesNum = verifyDate(chartSeries);
            int classifyNum = verifyDate(chartClassify);
            // 高级计算校验
            for (FieldAttrPojo fieldAttrPojo : fieldAttrPojoList) {
                JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
                if (CollectionsUtil.isEmpty(advancedComputing) || Objects.equals(advancedComputing.getString(0), AdvancedComputingFirstEnum.NONE.getAlias())) {
                    continue;
                }
                // 同环比校验
                if (Objects.equals(advancedComputing.getString(0), AdvancedComputingFirstEnum.YEAR_CHAIN.getAlias())) {
                    // 校验汇总方式
                    if (!Objects.equals(fieldAttrPojo.getAggType(), AggTypeEnum.SUM.getAlias())
                            && !Objects.equals(fieldAttrPojo.getAggType(), AggTypeEnum.AVG.getAlias())
                            && !Objects.equals(fieldAttrPojo.getAggType(), AggTypeEnum.COUNT.getAlias())) {
                        throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224071);
                    }
                    int dateNum;
                    if (Objects.equals(chartEntityEtx.getChartType(), ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())) {
                        // 统计表校验行+列是否有且只有一个日期字段
                        dateNum = rowDateNum + colDateNum;
                    } else {
                        // 统计图校验系列不是日期，分类是日期
                        if (seriesNum != 0) {
                            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224072);
                        }
                        dateNum = classifyNum;
                    }
                    if (dateNum != 1) {
                        throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224072);
                    }
                }
            }
        } catch (NullPointerException e) {
            LOG.error("统计图表保存高级计算出错:", e);
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224018);
        }
    }

    private int verifyDate(JSONArray groupAttrArr) {
        int dateNum = 0;
        if (CollectionsUtil.isNotEmpty(groupAttrArr)) {
            for (Object groupAttr : groupAttrArr) {
                FieldAttrEntity fieldAttrEntity = JSON.parseObject(JSON.toJSONString(groupAttr), FieldAttrEntity.class);
                if (EsUtil.isDateByEsalias(fieldAttrEntity)) {
                    dateNum++;
                }
            }
        }
        return dateNum;
    }

    private boolean isLinkedOrMultiFlag(ChartEntity entity, boolean linkedOrMultiFlag, JSONArray rowGroupAttr) {
        for (int i = 0; i < rowGroupAttr.size(); i++) {
            JSONObject jSONObject = rowGroupAttr.getJSONObject(i);
            if(Objects.equals(FieldTypeEnum.OWNERID.getAlias(),jSONObject.getString("attr")) || Objects.equals(FieldTypeEnum.OWNERID.getAlias(),jSONObject.getString("originalAttr"))  || Objects.equals(FieldTypeEnum.OWNERID.getType(),jSONObject.getInteger("fieldType"))){
                entity.setMuti(0);
                linkedOrMultiFlag = true;
            }
        }
        return linkedOrMultiFlag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChartSaveVO chartValueSave(ChartValueSaveDTO chartValueSaveDTO) throws XbbException {
        ChartSaveVO chartSaveVO = new ChartSaveVO();
        ChartValueSaveEntity chartValueSaveEntity = chartValueSaveDTO.getChart();
        ChartTypeEnum chartTypeEnum = ChartTypeEnum.getByCode(chartValueSaveEntity.getChartType());
        if (chartTypeEnum == null) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224013);
        }
        ChartEntity entity = new ChartEntity();
        BeanUtil.copyProperties(chartValueSaveEntity,entity);
        entity.setCreatorId(chartValueSaveDTO.getUserId());
        entity.setCorpid(chartValueSaveDTO.getCorpid());
        ExplainsPojo explainsPojo = new ExplainsPojo();
        explainsPojo.setUnitValue(chartValueSaveEntity.getUnitValue());
        entity.setExplains(JSONObject.parseObject(JSONObject.toJSON(explainsPojo).toString()));
        // 处理过滤条件
        handleFilter(entity);
        // 保存
        ChartCustomSaveVO chartCustomSaveVO;
        ChartCustomSaveDTO chartCustomSaveDTO = new ChartCustomSaveDTO();
        BeanUtil.copyProperties(chartValueSaveDTO, chartCustomSaveDTO);
        chartCustomSaveDTO.setChartEntity(entity);
        switch (chartTypeEnum) {
            case VALUE:
                chartCustomSaveVO = customSave4board(chartCustomSaveDTO);
                break;
            case PK_CUSTOM:
                chartCustomSaveVO = customSave4Pk(chartCustomSaveDTO);
                break;
            default:
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224013);
        }
        // 记录日志
        String userName = chartValueSaveDTO.getLoginUserName();
        String memo = String.format(chartCustomSaveVO.getLogMemoUpdateTemplate(), userName ,entity.getName());
        mongoLogHelp.buildLog(chartValueSaveDTO.getCorpid(), chartValueSaveDTO.getUserId(), userName, OperateModuleTypeEnum.CHART, chartCustomSaveVO.getOperateTypeEnum(), entity.getId().toString(), entity.getName(), memo, chartValueSaveDTO.getHttpHeader());
        chartSaveVO.setId(chartCustomSaveVO.getId());
        return chartSaveVO;
    }


    @Override
    public ChartSaveVO chartSystemValueSave(ChartSystemValuePojo chartSystemValuePojo) throws XbbException {
        ChartSaveVO chartSaveVO = new ChartSaveVO();
        ChartEntity chartEntity = new ChartEntity();
        BeanUtil.copyProperties(chartSystemValuePojo,chartEntity);
        chartModel.update(chartEntity);
        chartSaveVO.setId(chartEntity.getId());
        return chartSaveVO;
    }

    @Override
    public ChartEditVO chartEdit(ChartEditDTO chartEditDTO) throws XbbException {
        ChartEditVO chartEditVO = new ChartEditVO();
        ChartEntity chartEntity = chartCustomModel.getByKey(chartEditDTO.getChartId(), chartEditDTO.getCorpid());
        if(chartEntity == null ){
            throw  new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012);
        }
        //兼容脏数据，driverSource中没有distributorMark标记，前端回显有问题
        JSONObject driverSources = chartEntity.getDriverSources();
        SlaveSourcePojo slaveSourcePojo = driverSources.toJavaObject(SlaveSourcePojo.class);
        Integer distributorMark = slaveSourcePojo.getDistributorMark();
        if(Objects.isNull(distributorMark)){
            PaasFormEntityExt paasFormEntityExt = new PaasFormEntityExt();
            Long formId = slaveSourcePojo.getFormId();
            String corpid = chartEntity.getCorpid();
            if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), slaveSourcePojo.getBusinessType())) {
                WorkOrderFormEntity workOrderFormEntity = workOrderFormModel.getByKey(formId, corpid);
                if (Objects.isNull(workOrderFormEntity)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_NOT_EXIST);
                }
                BeanUtil.copyProperties(workOrderFormEntity, paasFormEntityExt);
            } else {
                paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
            }
            if(Objects.isNull(paasFormEntityExt) || Objects.equals(paasFormEntityExt.getDel(),DelEnum.DELETE.getDel())){
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_NOT_EXIST);
            }
            driverSources.put(StringConstant.DISTRIBUTOR_MARK,paasFormEntityExt.getDistributorMark());
        }

        ChartEntityEtx entityEtx = new ChartEntityEtx();
        BeanUtil.copyProperties(chartEntity, entityEtx);
        JSONArray search = chartEntity.getSearch();
        if (search != null && !search.isEmpty()) {
            entityEtx.setHasSearch(1);
        } else {
            entityEtx.setHasSearch(0);
        }
        JSONObject explains = chartEntity.getExplains();
        if(explains != null ){
            ExplainsPojo explainsPojo = explains.toJavaObject(ExplainsPojo.class);
            entityEtx.setFrozeColumDone(explainsPojo.getFrozeColumDone());
            entityEtx.setFrozeColum(explainsPojo.getFrozeColum());
            entityEtx.setUnitValue(explainsPojo.getUnitValue());
            entityEtx.setMap(explainsPojo.getMap());
            entityEtx.setFunnel(explainsPojo.getFunnel());
            entityEtx.setMapDistrict(explainsPojo.getMapDistrict());
        }
        chartEditVO.setChart(entityEtx);
        return chartEditVO;
    }

    @Override
    public ChartSavePojo chartListEdit(ChartListEditDTO chartListEditDTO) throws XbbException {
        ChartSavePojo chartSavePojo = new ChartSavePojo();
        ChartListDTO chartListDTO = new ChartListDTO();
        BeanUtil.copyProperties(chartListEditDTO,chartListDTO);
        String corpid = chartListEditDTO.getCorpid();
        //自定义报表原样返回
        chartListDTO.setChartTypeIn(null);
        try {
            Map<String, Object> map = BeanUtil.convertBean2Map(chartListDTO, true);
            List<ChartEntity> list = chartCustomModel.findEntitys(map);
            //只读库内的即可选择仪表盘也会触发系统图表初始化
            list.addAll(chartModel.findEntitys(map));
            List<ChartEntityEtx> listExt = new ArrayList<>();
            //查询仪表盘全局样式
            ChartCategoryEntity chartCategoryEntity = chartCategoryModel.getByKey(chartListEditDTO.getCategoryId(), corpid);
            chartSavePojo.setGlobalStyleOption(chartCategoryEntity.getGlobalStyleOption());
            // 单维度多指标权限(旗舰版才有)
            Boolean isUltimate = Objects.equals(packageHelp.getFeeType(chartListDTO.getCorpid()), PackageTypeEnum.ULTIMATE.getType());
            chartSavePojo.setSingleDimensionPermissions(isUltimate);
            chartSavePojo.setDataWarningPermissions(isUltimate);
            // 图表数量限制
            Integer limitNum = commonHelp.getChartLimit(chartListDTO.getCorpid(),ChartLimitTypeEnum.CHART_NUM_LIMIT.getAlias());
            chartSavePojo.setChartNumLimit(limitNum);
            if (list.size() == 0){
                chartSavePojo.setChartList(listExt);
                return chartSavePojo;
            }

            List<Long> formIdList = new ArrayList<>();
            List<PaasFormExplainEntity> explainEntityList = new ArrayList<>();
            //工单的解释信息特殊处理（只存在查询表,单数据源的情况）
            if (XbbRefTypeEnum.WORK_ORDER.getCode() == list.get(0).getDriverSources().getIntValue("businessType")) {
                Long formId = list.get(0).getDriverSources().getLong("formId");
                WorkOrderExplainEntityExt tempEntity = workOrderExplainModel.getByFormId(formId, chartListDTO.getCorpid());
                PaasFormExplainEntity paasFormExplainEntity = new PaasFormExplainEntity(tempEntity.getCorpid(),tempEntity.getAppId(),tempEntity.getMenuId(),formId,1,tempEntity.getExplains(),tempEntity.getCreatorId(),tempEntity.getAddTime(),tempEntity.getUpdateTime(),tempEntity.getDel(), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.WORK_ORDER.getCode(), DistributorMarkEnum.OTHER.getCode());
                explainEntityList.add(paasFormExplainEntity);
            }
            else{//除工单外的遍历list取formId存到集合中
                for (ChartEntity chartEntity : list) {
                    JSONObject driverSources = chartEntity.getDriverSources();
                    formIdList.add(driverSources.getLong(StringConstant.FORM_ID));
                    if(CollectionUtils.isNotEmpty(chartEntity.getSlaveSources())){
                        chartResultHelp.extractIdList(formIdList,chartEntity.getSlaveSources());
                    }
                }
                //根据formId集合查询相关解释
                if (CollectionUtils.isNotEmpty(formIdList)) {
                    Set<Long> temp = new HashSet<>(formIdList);
                    Map<String, Object> paramMap = new HashMap<>();
                    paramMap.put("formIdIn", temp);
                    paramMap.put("corpid", corpid);
                    paramMap.put("del",0);
                    explainEntityList = paasFormExplainModel.list(paramMap);
                }
            }
            // 获取套餐内数量的chartId
            List<Long> chartIdList = updatePackageRedisService.getPackageTotalChartId(corpid);
            // 获取套餐下的功能
            List<String> featureList = packageHelp.getFeatureList(corpid);
            Integer num = updatePackageRedisService.getUnusedNumPackageLimit(corpid, ValueAddedTypeEnum.CUSTOM_CHART_NUM);
            boolean isAdmin = chartListEditDTO.getLoginUser().isAdmin();
            List<Long> cusChartIdIn = new ArrayList<>();
            //设置图表编辑页的操作按钮
            List<ChartEditOpEnum> baseOpList = ChartEditOpEnum.getBaseOpList(null);
            for (ChartEntity chartEntity : list) {
                specialDriverSourceReturnChange(chartEntity);
                if (Objects.equals(chartEntity.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
                    JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
                    JSONArray colGroupAttr = chartEntity.getColGroupAttr();
                    //单表还是多表
                    Integer single = chartEntity.getSingle();
                    //关联数据
                    if (!EsUtil.getSingle(chartEntity)) {
                        single = 0;
                    }
                    updateFormName(corpid, chartEntity, single);
                    //如果是数据集，字段和explain里可能就不再对应，originalAttr多层的时候可能也不对应  TODO 暂时不处理更新解释
                    if(!Objects.equals(chartEntity.getSingle(), ChartSourceEnum.DATESET.getCode())){
                        updateExplainChartAttr(explainEntityList, chartEntity, rowGroupAttr, colGroupAttr, single);
                    }else{
                        //更新数据集名称
                        resetDataName(chartEntity);
                    }
                    //同步数据源的相关信息
                    synchroChartSource(chartEntity,explainEntityList);
                    //全局搜素
                    if(Objects.equals(chartEntity.getChartType(),ChartTypeEnum.MULTIPLE_SEARCH.getCode())){
                        JSONArray search = chartEntity.getSearch();
                        BeanUtil.copyProperties(chartEntity,chartSavePojo);
                        chartSavePojo.setChartId(chartEntity.getId());
                        if (search != null && !search.isEmpty()) {
                            chartSavePojo.setHasSearch(1);
                            chartSavePojo.setSearch(search);
                        }
                        continue;
                    }
//                JSONArray groupAttr = chartEntity.getGroupAttr();
                    rowGroupAttr = chartEntity.getRowGroupAttr();
                    if (Objects.nonNull(rowGroupAttr)) {
                        relatedProductAttr(rowGroupAttr);
                    }
                    colGroupAttr = chartEntity.getColGroupAttr();
                    if (Objects.nonNull(colGroupAttr)) {
                        relatedProductAttr(colGroupAttr);
                    }else {
                        chartEntity.setColGroupAttr(new JSONArray());
                    }
                    // 自定义单位转换,英文不支持单位
                    if (Objects.equals(LocaleContextHolder.getLocale().getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE)) {
                        chartEntity.setUnit("");
                    } else {
                        String unit = customHelp.setUnit(chartEntity);
                        chartEntity.setUnit(unit);
                    }
                }
                mapAndFunnelExplains(chartEntity,null);
                ChartEntityEtx chartEntityEtx = getChartEntityEtx(chartEntity);
                if (StatisticsTypeEnum.SYSTEM_STATISTIC.getCode() == chartEntity.getStatisticsType()) {
                    //设置是否是图和表的字段
                    setIfChartAndTable(chartEntityEtx);
                    setChartSearch(chartEntityEtx);
                } else if (Objects.equals(ChartTypeEnum.PK_CUSTOM.getCode(), chartEntity.getChartType())) {
                    // 自定义pk特殊处理
                    JSONArray search = new JSONArray();
                    // 默认置入这两个筛选
                    search.add(FilterConditionEnum.TIME_ALL.getCode());
                    search.add(FilterConditionEnum.ORGANIZATION_ALL.getCode());
                    chartEntityEtx.setSearch(search);
                    //设置hasSearch属性
                    chartEntityEtx.setHasSearch(ChartConstant.HAS_SEARCH);
                }
                // 公司套餐校验
                packageHelp.companyPackageVerify(isAdmin,chartEntityEtx,chartIdList,num,featureList);
                listExt.add(chartEntityEtx);
                cusChartIdIn.add(chartEntity.getId());
            }
            //处理图表的操作按钮
            dealChartOpEdit(corpid,listExt);
            //判断是否开启了国际化,返回是否展示国际化图标的标识
            CompanyConfigEntity entity = companyConfigModel.getByConfigAlias(CompanyConfigEnum.I18N_WHITE.getAlias(), PaasConstant.DEFAULT_DATA_CORPID);
            String value = CompanyConfigEnum.I18N_WHITE.getValue();
            if (Objects.nonNull(entity)) {
                value = entity.getConfigValue();
            }
            List<String> whiteList = JsonHelperUtil.parseArray(value, String.class);
            boolean flag = CollectionsUtil.isNotEmpty(whiteList) && whiteList.contains(chartListEditDTO.getCorpid());
            chartSavePojo.setMultiLang(flag);
            //只有自定义图表有钻取设置
            List<ChartDrillEntity> drillList = chartDrillModel.findByChartId(corpid, StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), cusChartIdIn);
            if (CollectionsUtil.isNotEmpty(drillList)) {
                //自定义图表id - 层级信息数组
                Map<Long, JSONArray> cidDrillMap = drillList.stream().collect(Collectors.toMap(d -> d.getChartId(), d -> d.getDrill()));
                //处理钻取信息
                for (ChartEntityEtx entityEtx : listExt) {
                    JSONArray drill = cidDrillMap.get(entityEtx.getId());
                    if (Objects.nonNull(drill)) {
                        entityEtx.setDrill(drill);
                    }
                }
            }
            chartSavePojo.setChartList(listExt);
        } catch (XbbException e) {
            throw e;
        }catch (Exception e){
            LOG.error("图表数据库查询报错",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return chartSavePojo;
    }

    /**
     * 同步图表的数据源相关配置
     *
     * @param chartEntity
     * @author zyy
     * @date 2023/4/19
     * @version v1.0
     */
    private void synchroChartSource(ChartEntity chartEntity,List<PaasFormExplainEntity> paasFormExplainEntityList) {
        if(CollectionUtils.isEmpty(paasFormExplainEntityList) || Objects.isNull(chartEntity)){
            return;
        }
        if(ChartSourceEnum.isDataSet(chartEntity.getSingle())){
            return;
        }

        Map<Long, String> explainMap = paasFormExplainEntityList.stream().collect(Collectors.toMap(PaasFormExplainEntity::getFormId, PaasFormExplainEntity::getExplains));
        //获取主表数据
        JSONObject driverSources = chartEntity.getDriverSources();
        Long masterFormId = driverSources.getLong(StringConstant.FORM_ID);
        JSONArray masterFieldDetailInfoArray = JSONArray.parseArray(explainMap.get(masterFormId));

        //更新关联字段数据源的字段名， 从数据源非关联字段的话（如直接进行比多表配置）则不做处理
        JSONArray slaveSources = chartEntity.getSlaveSources();
        if(CollectionUtils.isEmpty(slaveSources)){
            return;
        }
        List<SlaveSourcePojo> sourcePojos = slaveSources.toJavaList(SlaveSourcePojo.class);
        //根据从表中的关联字段driveLinkedAttr，拿到主表中对应字段的实时attrName
        for (SlaveSourcePojo sourcePojo : sourcePojos) {
            String driveLinkedAttr = sourcePojo.getDriveLinkedAttr();
            if (StringUtils.isBlank(driveLinkedAttr)){
                continue;
            }

            JSONObject checkAttr = (JSONObject) masterFieldDetailInfoArray.stream().filter(obj -> {
                JSONObject jsonObject = (JSONObject) obj;
                return StringUtils.isNotBlank(jsonObject.getString("attr")) && jsonObject.getString("attr").equals(driveLinkedAttr);
            }).findFirst().orElse(null);
            if(Objects.isNull(checkAttr)){
                continue;
            }
            String realAttrName = checkAttr.getString(StringConstant.ATTR_NAME);
            sourcePojo.setName(realAttrName);
            sourcePojo.setLinkedSourceName(Collections.singletonList(realAttrName));
        }
        chartEntity.setSlaveSources(JSONArray.parseArray(JSON.toJSONString(sourcePojos)));
    }

    /**
     * 特殊的数据源查询变更逻辑
     *
     * @param dataSourceAttrDTO
     * @param sources
     */
    private void specialDriverSourceQueryChange(DataSourceAttrDTO dataSourceAttrDTO, List<SlaveSourcePojo> sources) {
        //工单2.0自定义图表特殊逻辑(BusinessType=20300 && Single=1 && SpecialField=VersionId),显式加入WorkOrderV2NodeLogInfo表参数
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER_V2.getCode(), dataSourceAttrDTO.getDriverSources().getInteger(StringConstant.BUSINESS_TYPE))
                && Objects.equals(BasicConstant.ONE, dataSourceAttrDTO.getSingle())
                && Objects.equals(dataSourceAttrDTO.getSpecialField(), StringConstant.VERSION_ID)){
            SlaveSourcePojo tempSlaveSourcePojo = new SlaveSourcePojo();
            tempSlaveSourcePojo.setFormId(0L);
            tempSlaveSourcePojo.setSaasMark(SaasMarkEnum.SAAS.getCode());
            tempSlaveSourcePojo.setBusinessType(XbbRefTypeEnum.WORK_ORDER_V2_NODE_LOG_INFO.getCode());
            sources.add(tempSlaveSourcePojo);
        }
    }

    /**
     * 特殊的数据源返回变更逻辑
     *
     * @param chartEntity
     */
    private void specialDriverSourceReturnChange(ChartEntity chartEntity){
        JSONObject driverSources = chartEntity.getDriverSources();
        JSONArray slaveSources = chartEntity.getSlaveSources();
        //工单2.0自定义图表特殊逻辑(DriverSources.businessType=20350),变更DriverSource=WorkOrderV2,并且从SlaveSources中移除WorkOrderV2
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER_V2_NODE_LOG_INFO.getCode(), driverSources.getInteger(StringConstant.BUSINESS_TYPE))){
            driverSources = (JSONObject) slaveSources.stream()
                    .filter(o -> Objects.equals(XbbRefTypeEnum.WORK_ORDER_V2.getCode(), ((JSONObject) o).getInteger(StringConstant.BUSINESS_TYPE)))
                    .findFirst().orElse(null);
            slaveSources.removeIf(o -> Objects.equals(XbbRefTypeEnum.WORK_ORDER_V2.getCode(), ((JSONObject) o).getInteger(StringConstant.BUSINESS_TYPE)));
        }
        chartEntity.setDriverSources(driverSources);
        chartEntity.setSlaveSources(slaveSources);
    }

    /**
     * 特殊的数据源保存变更逻辑
     *
     * @param chartEntityEtx
     */
    private void specialDriverSourceSaveChange(ChartEntityEtx chartEntityEtx) {
        //工单2.0自定义图表特殊逻辑(BusinessType=20300 && Single=1),数据源转换为DriverSource=WorkOrderV2NodeLogInfo,SlaveSource=WorkOrderV2并添加连表字段
        if (Objects.equals(chartEntityEtx.getSingle(), BasicConstant.ONE) &&
                Objects.equals(XbbRefTypeEnum.WORK_ORDER_V2.getCode(), chartEntityEtx.getDriverSources().getInteger(StringConstant.BUSINESS_TYPE))){
            JSONObject driverSources = chartEntityEtx.getDriverSources();
            driverSources.put("linkAttr", "id");
            driverSources.put("fieldType", FieldTypeEnum.DATAID.getType());
            JSONObject slaveSource = (JSONObject) driverSources.clone();
            chartEntityEtx.getSlaveSources().add(0, slaveSource);
            driverSources.put("businessType", XbbRefTypeEnum.WORK_ORDER_V2_NODE_LOG_INFO.getCode());
            driverSources.put("linkAttr", StringConstant.WORK_ORDER_ID);
            //如果有其他关联数据表,则需要将关联字段一并写入
            if(chartEntityEtx.getSlaveSources().size() > BasicConstant.ONE){
                JSONObject o = (JSONObject)JSONObject.toJSON(chartEntityEtx.getSlaveSources().get(1));
                driverSources.put("linkAttrB", o.getString("driveLinkedAttr"));
            }
            driverSources.put("secondFieldType", FieldTypeEnum.DATAID.getType());
            driverSources.put("menuId", 0);
            driverSources.put("formId", 0);
            driverSources.put("id", 0);
        }
    }

    private void resetDataName(ChartEntity chartEntity) throws XbbException {
        if(Objects.isNull(chartEntity)){
            return;
        }
        JSONObject driverSources = chartEntity.getDriverSources();
        //图表中存储的数据集名称
        String currentName = driverSources.getString(XbbConstant.SOURCE_NAME);
        Long dataSetId = driverSources.getLong(XbbConstant.DATA_SET_ID);
        DataSetEntity dataSetEntity;
        try {
            dataSetEntity = dataSetHelp.getDataSetEntity(dataSetId, chartEntity.getCorpid());
        }catch (XbbException xbbException){
            return;
        }
        //数据集使用的名称
        String useName = dataSetEntity.getName();
        if(StringUtils.equals(currentName,useName)){
            return;
        }
        driverSources.put(XbbConstant.SOURCE_NAME,useName);
    }

    /**
     * 处理图表操作按钮
     *
     * @param corpid 公司唯一标识
     * @param listExt 图表实体
     * @author zyy
     * @date 2022/11/21
     * @version v1.0
     */
    public void dealChartOpEdit(String corpid,List<ChartEntityEtx> listExt) {
        //获取数据集图表
        List<ChartEntityEtx> dsChartList = listExt.stream().filter(chart -> ChartSourceEnum.isDataSet(chart.getSingle()) && Objects.nonNull(chart.getDataSetCompareTime())).collect(Collectors.toList());
        List<DataSetEntity> dataSetEntityList = dataSetHelp.dataSetEntityList(corpid,dsChartList);

        //分别处理图表操作按钮
        for (ChartEntityEtx chartEntityEtx : listExt) {
            if(dsChartList.contains(chartEntityEtx)){
                //匹配对应的数据集实体
                Long dataSetId = chartEntityEtx.getDriverSources().getLong(XbbConstant.DATA_SET_ID);
                DataSetEntity dataSetEntity = null;
                for (DataSetEntity entity : dataSetEntityList) {
                    if(Objects.equals(dataSetId,entity.getId())){
                        dataSetEntity = entity;
                        break;
                    }
                }

                List<ChartEditOpEnum> resultOpEnums = ChartEditOpEnum.getBaseOpList(null);
                //判断数据集是否为空或已删除
                if(Objects.isNull(dataSetEntity) || Objects.equals(DelEnum.DELETE.getDel(),dataSetEntity.getDel())){
                    //只保留删除按钮
                    resultOpEnums = resultOpEnums.stream().filter(editOp -> Objects.equals(ChartEditOpEnum.DEL, editOp)).collect(Collectors.toList());
                }else{
                    try {
                        //对比图表与数据的关联时间
                        if(dataSetHelp.compareDataSetTime(chartEntityEtx, chartEntityEtx.getDataSetCompareTime(),dataSetEntity)){
                            //只保留编辑、删除
                            resultOpEnums = resultOpEnums.stream().filter(editOp -> Objects.equals(ChartEditOpEnum.DEL, editOp) || Objects.equals(ChartEditOpEnum.EDIT,editOp)).collect(Collectors.toList());
                        }
                    }catch (XbbException e){
                        //出现异常统一只保留删除按钮
                        resultOpEnums = resultOpEnums.stream().filter(editOp -> Objects.equals(ChartEditOpEnum.DEL, editOp)).collect(Collectors.toList());
                    }
                }
                chartEntityEtx.setEditOp(ChartEditOpEnum.getEnumList(resultOpEnums));
                continue;
            }
            //普通图表给默认操作按钮
            chartEntityEtx.setEditOp(ChartEditOpEnum.getEnumList(ChartEditOpEnum.getBaseOpList(null)));
        }
    }

    private void updateExplainChartAttr(List<PaasFormExplainEntity> explainEntityList, ChartEntity chartEntity,  JSONArray rowGroupAttr, JSONArray colGroupAttr, Integer single) throws XbbException {
        JSONArray displayAttr = chartEntity.getDisplayAttr();
        JSONArray chartClassify = chartEntity.getChartClassify();
        JSONArray chartSeries = chartEntity.getChartSeries();
        JSONArray summaryAttr = chartEntity.getSummaryAttr();
        JSONArray searchAttr = chartEntity.getSearch();
        if (CollectionsUtil.isNotEmpty(displayAttr)) {
            displayAttr = chartResultService.updateExplain(displayAttr, explainEntityList, single, chartEntity.getCorpid());
            checkLabelName(displayAttr);
            chartEntity.setDisplayAttr(displayAttr);
        }
        if (CollectionsUtil.isNotEmpty(rowGroupAttr)) {
            rowGroupAttr = chartResultService.updateExplain(rowGroupAttr, explainEntityList, single, chartEntity.getCorpid());
            checkLabelName(rowGroupAttr);
            chartEntity.setRowGroupAttr(rowGroupAttr);
        }
        if (CollectionsUtil.isNotEmpty(colGroupAttr)) {
            colGroupAttr = chartResultService.updateExplain(colGroupAttr, explainEntityList, single, chartEntity.getCorpid());
            checkLabelName(colGroupAttr);
            chartEntity.setColGroupAttr(colGroupAttr);
        }
        if (CollectionsUtil.isNotEmpty(chartClassify)) {
            chartClassify = chartResultService.updateExplain(chartClassify, explainEntityList, single, chartEntity.getCorpid());
            checkLabelName(chartClassify);
            chartEntity.setChartClassify(chartClassify);
        }
        if (CollectionsUtil.isNotEmpty(chartSeries)){
            chartSeries = chartResultService.updateExplain(chartSeries, explainEntityList, single, chartEntity.getCorpid());
            checkLabelName(chartSeries);
            chartEntity.setChartSeries(chartSeries);
        }
        if (CollectionsUtil.isNotEmpty(searchAttr)) {
            searchAttr = chartResultService.updateSearchExplain(searchAttr, explainEntityList, single, chartEntity.getCorpid());
            checkLabelName(searchAttr);
            chartEntity.setSearch(searchAttr);
        }
        if (CollectionsUtil.isNotEmpty(summaryAttr)) {
            summaryAttr = chartResultService.updateExplain(summaryAttr, explainEntityList, single, chartEntity.getCorpid());
            checkLabelName(summaryAttr);
            chartEntity.setSummaryAttr(summaryAttr);
        }
    }

    /**
     * 更新form表单的名字 （根据businessType判断是否是工单）
     * @param corpid, chartEntity, single
     * @return void
     * @author weiming
     * @date 2020/12/16 16：10
     * @since v1.0
     * @version v1.0
     */
    private void updateFormName(String corpid, ChartEntity chartEntity, Integer single) throws XbbException {
        JSONObject driverSources = chartEntity.getDriverSources();
        Long formId = driverSources.getLong("formId");
        Integer businessType = driverSources.getInteger("businessType");
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)){
            WorkOrderFormEntityExt workOrderFormEntityExt = workOrderFormModel.getByKey(formId, corpid);
            //workOrderFormModel.getByKey sql解析中加了del=0
            if(workOrderFormEntityExt != null){
                driverSources.put("name",workOrderFormEntityExt.getName());
            }
        }else{
            //如果是产品子表的话先不走这边，还是按照上一次存库的名称
            if (Objects.nonNull(BIProductReformEnum.getEnumByProductBusinessType(businessType))) {
                PaasFormRefEntity paasFormRefEntity = paasFormRefModel.getMainFormIdByFormId(formId, corpid);
                if (paasFormRefEntity != null){
                    String proudctAttr = BIProductReformEnum.getProductAttr(businessType, paasFormRefEntity.getType());
                    PaasFormEntityExt mainPaasForm = paasFormModel.getByKey(paasFormRefEntity.getMainFormId(), corpid);
                    PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(paasFormRefEntity.getMainFormId(), corpid);
                    if (paasFormExplainEntity == null) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                    }
                    List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
                    Map<String, Object> explainMap = explainList.stream().collect(Collectors.toMap(FieldAttrEntity::getAttr, fieldAttrEntity -> fieldAttrEntity));
                    FieldAttrEntity productFieldAttrEnity = (FieldAttrEntity) explainMap.get(proudctAttr);
                    String formName = "";
                    if (!BIProductReformEnum.getMultipleProductCodeList().contains(businessType)) {
                        formName = String.format(I18nMessageUtil.getMessage(RelatedProductConstant.PRODUCT_LINK_NAME), mainPaasForm.getName());
                    }else {
                        formName = String.format(I18nMessageUtil.getMessage(RelatedProductConstant.PRODUCT_LINK_NAME_SEN), mainPaasForm.getName(), productFieldAttrEnity.getAttrName());
                    }
                    driverSources.put("name",formName);
                }
            } else {
                PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
                if (Objects.nonNull(paasFormEntityExt)) {
                    driverSources.put("name",paasFormEntityExt.getName());
                }
            }
        }
        chartEntity.setDriverSources(driverSources);
        if (Objects.equals(single,0)) {
            JSONArray slaveSources = chartEntity.getSlaveSources();
            List<Long> longList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (int i = 0; i < slaveSources.size(); i++) {
                JSONObject jsonObject = slaveSources.getJSONObject(i);
                JSONArray linkedSourceNames = jsonObject.getJSONArray("linkedSourceName");
                if (linkedSourceNames != null && linkedSourceNames.size() > 0) {
                    return;
                }
                Long formId1 = jsonObject.getLong("formId");
                longList.add(formId1);
            }
            HashMap<String, Object> params = new HashMap<>(7);
            params.put("idIn",longList);
            params.put("corpid", corpid);
            params.put("del", 0);
            List<PaasFormEntityExt> entitys = paasFormModel.findEntitys(params);
            Map<Long, String> collectMap = entitys.stream().collect(Collectors.toMap(PaasFormEntityExt::getId, PaasFormEntityExt::getName));
            JSONArray jsonArray = new JSONArray();
            for (int i = 0; i < slaveSources.size(); i++) {
                JSONObject jsonObject = slaveSources.getJSONObject(i);
                Long formId1 = jsonObject.getLong("formId");
                jsonObject.put("name",collectMap.get(formId1));
                jsonArray.add(jsonObject);
            }
            chartEntity.setSlaveSources(jsonArray);
        }
    }

    private void checkLabelName(JSONArray allTypeAttr) {
        for (int i = 0; i < allTypeAttr.size(); i++) {
            JSONObject jsonObject = allTypeAttr.getJSONObject(i);
            int fieldType = jsonObject.getIntValue("fieldType");
            String labelName = jsonObject.getString("labelName");
            String label = jsonObject.getString("label");
            String attrName = jsonObject.getString("attrName");
            if (label == null) {
                return;
            }
            String temp = Arrays.asList(label.split("--")).get(0);
            String tempStr = temp + "--" + attrName;
            if (Objects.equals(FieldTypeEnum.SUB_FORM.getType(),fieldType)){
                if (Objects.equals(labelName,label)){
                    jsonObject.put("labelName",tempStr);
                }
                jsonObject.put("label",tempStr);
                JSONArray jsonArray = jsonObject.getJSONObject("subForm").getJSONArray("items");
                JSONArray tempJsonArray =new JSONArray();
                for (int m = 0; m < jsonArray.size(); m++) {
                    JSONObject tempObject = jsonArray.getJSONObject(m);
                    if (Objects.equals(tempObject.getString("label"),tempObject.getString("labelName"))) {
                        tempObject.put("labelName",tempObject.getString("attrName"));
                    }
                    tempObject.put("label",tempObject.getString("attrName"));
                    JsonHelperUtil.addToJSONArray(tempJsonArray,tempObject);
                }
                jsonObject.getJSONObject("subForm").put("items",tempJsonArray);
            } else if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),fieldType)) {

            } else {
                if (Objects.equals(labelName, label)) {
                    jsonObject.put("labelName", tempStr);
                }
                jsonObject.put("label", tempStr);
            }
        }
    }

    private void relatedProductAttr(JSONArray groupAttr) {
        for (int i = 0; i < groupAttr.size(); i++) {
            JSONObject jsonObject = groupAttr.getJSONObject(i);
            String id = jsonObject.getString("id");
            //判断businessType和attr必须要属于产品
            if (XbbRefTypeEnum.PRODUCT.getCode() == jsonObject.getIntValue("businessType") && ProductEnum.CATEGORY_ID.getAttr().equals(id)) {
                JSONArray selectedCategory = jsonObject.getJSONArray("selectedCategory");
                String corpid = jsonObject.getString("corpid");
                //查出所有分类
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put("corpid", corpid);
                param.put("del",0);
                param.put("orderByStr", "sort ASC, update_time ASC ");
                List<ProductCategoryEntity> allCay = productCategoryModel.findEntitys(param);
                List<Long> categoryId = allCay.stream().map(ProductCategoryEntity::getId).collect(Collectors.toList());
                //遍历selectedCategory 如果所有分类不包含当前分类，selectedCategory删除这个分类
                for (int j = 0; j < selectedCategory.size(); j++) {
                    JSONObject tempObject = selectedCategory.getJSONObject(j);
                    Long tempId = tempObject.getLong("id");
                    if (!categoryId.contains(tempId)){
                        selectedCategory.remove(j);
                        j--;
                    }
                }
                jsonObject.put("selectedCategory",selectedCategory);
                groupAttr.set(i,jsonObject);
            }
        }
    }

    @Override
    public AttrConditionVO getAttrCondition(AttrConditionDTO attrConditionDTO) throws XbbException {
        AttrConditionVO attrConditionVO = new AttrConditionVO();
        Integer fiedType = attrConditionDTO.getFieldType();
        // 1：表头字段；2：汇总字段（值） 3.分组字段（分类、系列）
        Integer searchSourceAttr = attrConditionDTO.getSelectDisplayAttr();
        List<Integer> numIdList = FieldTypeEnum.esaliasTypeList().getNumIdList();
        List<Integer> timeIdList = FieldTypeEnum.esaliasTypeList().getTimeIdList();
        if(timeIdList.contains(fiedType)){
            if(Objects.equals(FieldUseLocationEnum.DISPLAYATTR.getCode(),searchSourceAttr)){
                String widgetName = I18nMessageUtil.getMessage(I18nStringConstant.DATA_FORMAT);
                attrConditionVO(attrConditionVO, DateFormatEnum.list(), widgetName, WidgetTypeEnum.RADIOTYPE.getAlias());
            }else{
                String widgetName = I18nMessageUtil.getMessage(I18nStringConstant.DATE_SUMMARY);
                attrConditionVO(attrConditionVO, DateTypeEnum.list(), widgetName, WidgetTypeEnum.RADIOTYPE.getAlias());
            }
        }else if(numIdList.contains(fiedType)){
            //1：表头字段；2：汇总字段（值） 3.分组字段（分类、系列）
            if(Objects.equals(FieldUseLocationEnum.SUMATTR.getCode(),searchSourceAttr)){
                String widgetName = I18nMessageUtil.getMessage(I18nStringConstant.AGGREGATE_PROPORTION);
                attrConditionVO(attrConditionVO, SwitchEnum.list(), widgetName,  WidgetTypeEnum.SWITCH.getAlias());
                //金额区分
                Integer  amountFlag = attrConditionDTO.getAmountFlag();
                if(Objects.equals(1,amountFlag)){
                    widgetName = I18nMessageUtil.getMessage(I18nStringConstant.AGGREGATION_METHOD);
                    attrConditionVO(attrConditionVO,  AggTypeEnum.list(), widgetName,  WidgetTypeEnum.RADIOTYPE.getAlias());
                }
            }
            String widgetName = I18nMessageUtil.getMessage(I18nStringConstant.DATA_FORMAT);
            attrConditionVO(attrConditionVO, DataFormatEnum.list(), widgetName,  WidgetTypeEnum.COMBO.getAlias());
        }
        return attrConditionVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChartDeleteVO chartDelete(ChartDeleteDTO chartDeleteDTO) throws XbbException {
        //塞入map
        Map<String, Object> map = BeanUtil.convertBean2Map(chartDeleteDTO, true);
        List<ChartEntity> list = chartCustomModel.findEntitys(map);
        //未删除成功的图表名称
        List<String> errorNameList = new ArrayList<>();
        //未删除成功的原因
        List<String> errorMsgList = new ArrayList<>();
        boolean systemFlag = false;
        long now = DateUtil.getInt();
        int count = 0;
        for (ChartEntity chartEntity : list) {
            Long chartId = chartEntity.getId();
            String name = chartEntity.getName();
            if (chartEntity.getDel().equals(1)) {
                //已删除的，无需处理
                continue;
            }
            Integer statisticsType = chartEntity.getStatisticsType();
            if (StatisticsTypeEnum.SYSTEM_STATISTIC.getCode() == statisticsType) {
                systemFlag = true;
                errorNameList.add(name);
                continue;
            }
            count++;
            chartEntity.setDel(1);
            chartEntity.setUpdateTime(now);
            chartCustomModel.update(chartEntity);

            // 自定义pk把分类也删了
            if (Objects.equals(chartEntity.getChartType(), ChartTypeEnum.PK_CUSTOM.getCode())) {
                ChartDTO chartDTO = new ChartDTO();
                BeanUtil.copyProperties(chartDeleteDTO, chartDTO);
                chartDTO.setChartEntity(chartEntity);
                List<ChartCategoryEntity> categoryEntityList = getCategoryList4Pk(chartDTO);
                if (CollectionUtils.isNotEmpty(categoryEntityList)) {
                    categoryEntityList.forEach(i -> i.setDel(DelEnum.DELETE.getDel()));
                    chartCategoryModel.updateBatch(categoryEntityList, chartDeleteDTO.getCorpid());
                }
            }

            String logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_DELETE_CHART_VALUE);
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
            // 记录日志
            String userName = chartDeleteDTO.getLoginUserName();
            String memo = String.format(logMemoUpdateTemplate, userName ,chartEntity.getName());
            mongoLogHelp.buildLog(chartDeleteDTO.getCorpid(), chartDeleteDTO.getUserId(), userName, OperateModuleTypeEnum.CHART, operateTypeEnum, chartEntity.getId().toString(), chartEntity.getName(), memo, chartDeleteDTO.getHttpHeader());
        }
        if (count == 0) {
            if (systemFlag) {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224048);
            }else {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224049);
            }
        }
        if (systemFlag) {
            errorMsgList.add(I18nMessageUtil.getMessage(StringConstant.ERROR_SYSTEM_CHART));
        }
        ChartDeleteVO chartDeleteVO = new ChartDeleteVO();
        chartDeleteVO.setErrorNameList(errorNameList);
        chartDeleteVO.setErrorMsgList(errorMsgList);
        return chartDeleteVO;
    }

    @Override
    public ShowTypeVO getShowType(ShowTypeDTO showTypeDTO) throws XbbException {
        ShowTypeVO showTypeVO = new ShowTypeVO();
        Integer chartType =  showTypeDTO.getChartType();
        List<AggsTypeClass>  chartTypeEnums;
        //如果为0，则为获取所有值
        if(Objects.equals(0,chartType)){
            chartTypeEnums =  ChartTypeEnum.getAllTeam();
        }else {
            ChartTypeEnum  chartTypeEnum = ChartTypeEnum.getByCode(chartType);
            if(chartTypeEnum == null){
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224015);
            }
            chartTypeEnums = ChartTypeEnum.getByTeam(chartTypeEnum.getTeam());
            // 非旗舰进行图表类型过滤
            if (!Objects.equals(packageHelp.getFeeType(showTypeDTO.getCorpid()),PackageTypeEnum.ULTIMATE.getType())){
                List<Integer> chartCodeList = ChartTypeEnum.getSeniorChartList().stream().map(ChartTypeEnum::getCode).collect(Collectors.toList());
                //过滤高级图表
                chartTypeEnums.removeIf(chart -> chartCodeList.contains(chart.getCode()));
            }
        }
        showTypeVO.setShowTypes(chartTypeEnums);
        return showTypeVO;
    }

    @Override
    public ChartMobileFavoriteSaveVO chartMobileFavoriteSave(ChartMobileFavoriteSaveDTO chartMobileFavoriteSaveDTO) throws XbbException {
        //是否收藏，1收藏，0取消收藏
        Integer favorite = chartMobileFavoriteSaveDTO.getFavorite();
        //塞入map
        Map<String, Object> map = BeanUtil.convertBean2Map(chartMobileFavoriteSaveDTO, true);
        map.put("userId", chartMobileFavoriteSaveDTO.getUserId());
        Integer categoryType = chartMobileFavoriteSaveDTO.getCategoryType();
        ChartCategoryTypeEnum chartCategoryTypeEnum = ChartCategoryTypeEnum.getEnumByCode(categoryType);
        boolean pkFlag = chartCategoryTypeEnum == ChartCategoryTypeEnum.PK_DEP || chartCategoryTypeEnum == ChartCategoryTypeEnum.PK_USER || chartCategoryTypeEnum == ChartCategoryTypeEnum.PK_CUSTOM;
        if (pkFlag) {
            map.put("categoryType", categoryType);
        }
        List<ChartFavoriteEntity> allFavoriteList = chartFavoriteModel.findEntitys(map);
        ChartFavoriteEntity entity = null;
        //查询启用的图表
        Set<Long> chartIdIn = new HashSet<>();
        Set<Long> chartCustomIdIn = new HashSet<>();
        for (ChartFavoriteEntity favoriteEntity : allFavoriteList) {
            Long chartId = favoriteEntity.getChartId();
            if (favoriteEntity.getDel() == 0) {
                //收藏的图表
                if (Objects.equals(favoriteEntity.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
                    chartCustomIdIn.add(chartId);
                } else {
                    chartIdIn.add(chartId);
                }
            }
            if (Objects.equals(chartMobileFavoriteSaveDTO.getChartId(), chartId)) {
                entity = favoriteEntity;
            }
        }
        //如果收藏图表，则需要所有收藏的开启图表个数不能超过10个（即需要查询所有收藏的图表里面处于开启状态的图表个数）
        boolean checkFlag = (favorite != null && favorite == 1) && (chartIdIn.size() + chartCustomIdIn.size() >= ChartLimitEnum.CHART_FAVORITE_MAX.getLimit());
        ChartMobileFavoriteSaveVO chartMobileFavoriteSaveVO = new ChartMobileFavoriteSaveVO();
        if (checkFlag) {
            if (entity != null && entity.getDel() == 0) {
                //说明该图表已经收藏，无需处理
                return chartMobileFavoriteSaveVO;
            }
            Integer count = 0;
            if (chartIdIn.size() > 0) {
                map.put("idIn", chartIdIn);
                map.put("enable", 1);
                map.put("del", 0);
                count = chartModel.getEntitysCount(map);
            }
            if (chartCustomIdIn.size() > 0) {
                map.put("idIn", chartCustomIdIn);
                map.put("enable", 1);
                map.put("del", 0);
                count += chartCustomModel.getEntitysCount(map);
            }
            if (count >= ChartLimitEnum.CHART_FAVORITE_MAX.getLimit()) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, ChartLimitEnum.CHART_FAVORITE_MAX.getMsg());
            }
        }
        long now = DateUtil.getInt();
        Integer del = 0;
        if (entity != null) {
            //判断移除与否
            del = entity.getDel();
            if (del == 1 && favorite == 0) {
                //已经不是收藏，无需再次取消
                return chartMobileFavoriteSaveVO;
            }
        }else {
            if (favorite == 0) {
                //取消本來就沒收藏过的图表，直接返回，无需处理
                return chartMobileFavoriteSaveVO;
            }
            entity = new ChartFavoriteEntity();
            BeanUtil.copyProperties(chartMobileFavoriteSaveDTO, entity, true);
            entity.setAddTime(now);
            entity.setCreatorId(chartMobileFavoriteSaveDTO.getUserId());
        }
        del = (favorite != null && favorite == 1)? 0: 1;
        entity.setDel(del);
        entity.setUpdateTime(now);
        entity.setSort(0);
        chartFavoriteModel.save(entity);

        return chartMobileFavoriteSaveVO;
    }

    @Override
    public ChartMobileListVO chartMobileList(ChartMobileListDTO chartMobileListDTO) throws XbbException {
        Long categoryId = chartMobileListDTO.getCategoryId();
        ChartMobileListVO chartMobileListVO = new ChartMobileListVO();
        //除了来自首页（发布到首页的仪表盘）外，没有图表查看权限的角色弹出，前端接收跳到首页
        UserVO loginUser = chartMobileListDTO.getLoginUser();
        Set<String> permSet = loginUser.getPermSet();
        if(!Objects.equals(chartMobileListDTO.getOriginOfChart(), OriginOfChartEnum.HOME_PAGE.getCode())){
            if(!permSet.contains(ChartProPermissionAliasEnum.CHART_VIEW.getAlias())){
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100128);
            }
        }
        chartMobileListVO.setCategoryId(categoryId);
        //收藏图表，要按照收藏的更新时间倒序排列
        Map<String, Object> chartMap = BeanUtil.convertBean2Map(chartMobileListDTO, true);
        chartMap.put("userId", chartMobileListDTO.getUserId());
        chartMap.put("orderByStr", "update_time DESC");
        chartMap.remove("statisticsType");
        List<ChartFavoriteEntity> favoriteList = chartFavoriteModel.findEntitys(chartMap);
        //使用完毕移除
        chartMap.remove("userId");
        //收藏图表id列表
        Set<Long> favoriteChartIdIn = new HashSet<>();
        //收藏自定义图表id列表
        Set<Long> favoriteChartCustomIdIn = new HashSet<>();
        //图表id--pk类型（ChartConstant内的PK_NO、PK_USER、PK_DEP、PK_DEP_USER）
        Map<Long, Integer> pkTypeMap = new HashMap<>(favoriteList.size());
        for (ChartFavoriteEntity entity : favoriteList) {
            Long chartId = entity.getChartId();
            int pkFlag = getPkFlag(entity.getCategoryType());
            Integer pkType = pkTypeMap.get(chartId);
            if (pkType == null) {
                //第一次，直接塞入
                pkTypeMap.put(chartId, pkFlag);
            }else if (pkType != pkFlag) {
                //两次不相等，则既有员工pk，又有部门pk
                pkTypeMap.put(chartId, ChartConstant.PK_DEP_USER);
            }
            if (Objects.equals(entity.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
                favoriteChartCustomIdIn.add(entity.getChartId());
            } else {
                favoriteChartIdIn.add(entity.getChartId());
            }
        }
        String corpid = chartMobileListDTO.getCorpid();
        // 初始化校验图表的相关数据
        List<Long> chartIdList = updatePackageRedisService.getPackageTotalChartId(corpid);
        List<String> featureList = packageHelp.getFeatureList(corpid);
        Boolean isAdmin = chartMobileListDTO.getLoginUser().isAdmin();
        Integer num = updatePackageRedisService.getUnusedNumPackageLimit(corpid, ValueAddedTypeEnum.CUSTOM_CHART_NUM);

        List<ChartEntityEtx> chartList = new ArrayList<>();
        if (CategoryEnum.CATEGORY_FAVORITE.getCode().equals(categoryId)) {
            //获取收藏图表ids：按照收藏图表的收藏时间倒序（updateTime倒序）
            if (favoriteChartIdIn.size() == 0 && favoriteChartCustomIdIn.size() == 0) {
                //说明无收藏图表
                return chartMobileListVO;
            }
            //只获取出收藏的图表
            List<ChartEntity> list = new ArrayList<>();
            if (favoriteChartIdIn.size() > 0) {
                chartMap.put("idIn", favoriteChartIdIn);
                list.addAll(chartModel.findEntitys(chartMap));
            }
            if (favoriteChartCustomIdIn.size() > 0) {
                chartMap.put("idIn", favoriteChartCustomIdIn);
                list.addAll(chartCustomModel.findEntitys(chartMap));
            }
            //chartId---图表实体
            Map<Long, ChartEntity> chartEntityMap = new HashMap<>(list.size());
            for (ChartEntity chartEntity : list) {
                chartEntityMap.put(chartEntity.getId(), chartEntity);
            }
            //最终根据收藏图表循环封装图表（pk和部门pk虽然是同一个chart，但是对于收藏根据categoryType的不同，要封装不同的图---可能同时存在两个）
            for (ChartFavoriteEntity favoriteEntity : favoriteList) {
                Long chartId = favoriteEntity.getChartId();
                ChartEntity chartEntity = chartEntityMap.get(chartId);
                if (chartEntity == null) {
                    continue;
                }
                ChartEntityEtx chartEntityEtx = getChartEntityEtx(chartEntity);
                Integer categoryType = favoriteEntity.getCategoryType();
                chartEntityEtx.setCategoryType(categoryType);
                chartEntityEtx.setFavorite(1);
                //设置单个系统图表的search
                if (StatisticsTypeEnum.SYSTEM_STATISTIC.getCode() == chartEntityEtx.getStatisticsType()) {
                    setChartSearch(chartEntityEtx);
                    //部门pk和员工pk的search特殊处理
                    JSONArray search = handlePkSearch(categoryType, chartEntityEtx);
                } else if (Objects.equals(ChartTypeEnum.PK_CUSTOM.getCode(), chartEntity.getChartType())) {
                    // 自定义pk特殊处理
                    JSONArray search = new JSONArray();
                    // 默认置入这两个筛选
                    search.add(FilterConditionEnum.TIME_ALL.getCode());
                    search.add(FilterConditionEnum.ORGANIZATION_ALL.getCode());
                    chartEntityEtx.setSearch(search);
                    //设置hasSearch属性
                    chartEntityEtx.setHasSearch(ChartConstant.HAS_SEARCH);
                }
                chartList.add(chartEntityEtx);
            }
        }else if (CategoryEnum.CATEGORY_SEARCH.getCode().equals(categoryId)){
            // 移动端搜素图表
            List<ChartCategoryEntity> categoryList = getCategoryByNameLike4App(chartMobileListDTO);
            chartMobileListVO.setCategoryId(categoryList.get(0).getId());
            // 前端需要知道是分组还是仪表板
            if (Objects.equals(categoryList.get(0).getParentId(),BasicConstant.ZERO_LONG)){
                chartMobileListVO.setCategoryType(1);
            }else {
                chartMobileListVO.setCategoryType(0);
            }
            return chartMobileListVO;
        } else if (categoryId >= 0) {
            //非收藏图表
            chartList.addAll(getChartsByCategory4App(chartMobileListDTO, categoryId, pkTypeMap, chartMap));
        }

        List<ChartEntityEtx> resultChartList = new ArrayList<>();
        JSONObject overAllPermissions = customHelp.chartOverallPermissions(chartMobileListDTO);
        Map<Long, List<Long>> subAllDepIdMap = departmentModel.getSubDepIdMap(corpid, false);

        // 处理钻取层级信息
        List<Long> idList = chartList.stream().map(ChartEntityEtx::getId).collect(Collectors.toList());
        //只有自定义图表有钻取设置
        List<ChartDrillEntity> drillList = chartDrillModel.findByChartId(corpid, StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), idList);
        Map<Long, JSONArray> allChartDrillMap = null;
        if (CollectionsUtil.isNotEmpty(drillList)) {
            //自定义图表id - 层级信息数组
            allChartDrillMap = drillList.stream().collect(Collectors.toMap(ChartDrillEntity::getChartId, ChartDrillEntity::getDrill));
        }

        //查询仪表盘全局样式
        //收藏图标的分类id为-1或者-2
        ChartCategoryEntity chartCategoryEntity = null;
        if (categoryId >= 0) {
            chartCategoryEntity = chartCategoryModel.getByKey(categoryId, corpid);
            if (Objects.nonNull(chartCategoryEntity)) {
                chartMobileListVO.setGlobalStyleOption(chartCategoryEntity.getGlobalStyleOption());
            }
        }

        //ck、旗舰版、且有钻取权限，则有钻取开关
        boolean chartDrill = customHelp.drillPermission(corpid, permSet);
        for (ChartEntityEtx chartEntityExt : chartList) {
            // 销售漏斗备注特殊处理
            String systemCode = chartEntityExt.getSystemCode();
            if (!StringUtil.isEmpty(systemCode)) {
                if(Objects.equals(systemCode, SystemCodeEnum.OPPORTUNITY_FUNNEL_CHART.getCode())){
                    chartEntityExt.setMemo(I18nMessageUtil.getMessage(StringConstant.OPPORTUNITY_FUNNEL_CHART_MEMO));
                }
            }
            //可见权限控制
            JSONObject permissionsJson = chartEntityExt.getPermissions();
            // 自定义pk的特殊处理：自定义pk的permissions从category中获取
            if (Objects.isNull(permissionsJson) && Objects.nonNull(chartCategoryEntity) && Objects.equals(chartEntityExt.getChartType(),ChartTypeEnum.PK_CUSTOM.getCode())){
                permissionsJson = chartCategoryEntity.getPermissions();
            }
            Map<String, Boolean> permissions = customHelp.isChartPermissions(permissionsJson, chartMobileListDTO, overAllPermissions, subAllDepIdMap);
            if (permissions.get(ChartProPermissionAliasEnum.CHART_VIEW.getAlias())) {
                // 控制联动设置入口的显隐
                dealLinkageDisplay(chartEntityExt,loginUser);
                // 处理钻取匹配信息
                dealDrillMatchInfo(chartDrill, allChartDrillMap, chartEntityExt);
                //组装联动相关数据供下游使用
                LinkageListParamPojo listParamPojo = initLinkageListParamPojo(chartList,chartEntityExt,overAllPermissions,chartMobileListDTO,subAllDepIdMap);
                //自定义图表处理一下图表交互按钮集合（历史数据explains内无图表交互配置，需要处理默认值）
                dealWithExplains(chartEntityExt, chartEntityExt.getChartType(),listParamPojo);
                // 公司套餐限制
                packageHelp.companyPackageVerify(isAdmin,chartEntityExt,chartIdList,num,featureList);
                resultChartList.add(chartEntityExt);
            }
        }

        JSONObject obj = new JSONObject();
        obj.put(ProPermissionAliasEnum.CHART_DRILL.getAlias(), chartDrill);
        chartMobileListVO.setChartPermissions(obj);
        chartMobileListVO.setChartList(resultChartList);
        return chartMobileListVO;
    }


    private LinkageListParamPojo initLinkageListParamPojo(List<ChartEntityEtx> chartList, ChartEntityEtx chartEntityExt, JSONObject overAllPermissions, ChartMobileListDTO chartMobileListDTO,Map<Long, List<Long>> subAllDepIdMap) {
        List<ChartEntity> list = new ArrayList<>();
        ChartEntity currentChart = null;
        for (ChartEntityEtx chart : chartList) {
            ChartEntity chartEntity = new ChartEntity();
            BeanUtil.copyProperties(chart,chartEntity);
            if(Objects.equals(chartEntityExt.getId(),chart.getId())){
                currentChart = chartEntity;
            }
            list.add(chartEntity);
        }
        //组装联动相关数据供下游使用
        return new LinkageListParamPojo(new ArrayList<>(list),currentChart,overAllPermissions,subAllDepIdMap,chartMobileListDTO);
    }

    /**
     * 通过nameLike查询图表是否存在
     * @param chartMobileListDTO 移动端图表查询条件
     * @return 如果没有则抛出异常，如果有则直接返回
     * @author 梅伟丁
     * @date 2022/4/14 14:09
     * @version 1.0
     */
    private List<ChartCategoryEntity> getCategoryByNameLike4App(ChartMobileListDTO chartMobileListDTO) throws XbbException {
        List<ChartCategoryEntity> categoryList = null;
        // 基础参数预处理
        chartMobileListDTO.postProcess();
        // 如果分组或仪表盘名称为空则
        if (StringUtil.isEmpty(chartMobileListDTO.getNameLike())){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224090, StatisticsServicesErrorCodeEnum.API_ERROR_224090.getMsg());
        }
        // 图表分类模糊查询参数赋值
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid",chartMobileListDTO.getCorpid());
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("enable", EnableEnum.OPEN.getCode());
        param.put("orderByStr", "parent_id ASC, sort DESC");
        param.put("start", 0);
        param.put("pageNum", 1);
        // 通过名称模糊查询(区分是中文还是英文)
        if (StringUtil.isNotEmpty(chartMobileListDTO.getLocale())){
            if (Objects.equals(chartMobileListDTO.getLocale(),Locale.CHINA.toString())){
                param.put("CNNameLike", chartMobileListDTO.getNameLike());
            }else {
                param.put("ENNameLike", chartMobileListDTO.getNameLike());
            }
        }
        categoryList = chartCategoryModel.findEntitys(param);
        // 如果没有则抛出异常，如果有则直接返回（为了效率，后端只返回categoryList，然后取第一个categoryId，具体跳转结果由前端查询）
        if (categoryList == null || categoryList.size() == 0){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224089, StatisticsServicesErrorCodeEnum.API_ERROR_224089.getMsg());
        }
        return categoryList;
    }

    /**
     * 图表初始化
     *
     * @param chartInitDTO 入参（包含corpid）
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartInitVO
     * @throws XbbException 父类异常
     * @author 徐俊杰
     * @date 2019/1/31 15:05
     * @since v1.0
     */
    @Override
    public ChartInitVO chartInit(ChartInitDTO chartInitDTO) throws XbbException {
        return chartInitHelp.chartInit(chartInitDTO);
    }

    /**
     * 系统图表的编辑(只修改权限)
     * @param chartSystemSavePojo 入参
     * @return ChartBatchSaveVo
     * @author zhouwq
     * @date 2019/4/30 16:12
     * @throws XbbException error
     */
    @Override
    public ChartBatchSaveVo chartPermissionsUpdate(ChartSystemSavePojo chartSystemSavePojo) throws XbbException {
        ChartBatchSaveVo chartBatchSaveVo = new ChartBatchSaveVo();
        ChartEntityEtx chartEntityEtx = chartSystemSavePojo.getChartEntity();

        // 自定义pk单独切走
        if (Objects.equals(chartEntityEtx.getChartType(), ChartTypeEnum.PK_CUSTOM.getCode())) {
            return pkCustomPermissionsUpdate(chartSystemSavePojo, chartEntityEtx, chartBatchSaveVo);
        }

        List <ChartSaveUuidVO> chartSaveUuidList = new ArrayList<>();
        ChartEntity entity = new ChartEntity();
        BeanUtil.copyProperties(chartEntityEtx, entity);
        entity.setButtonAttr(chartEntityEtx.getButtonPermissionList());
        // 跟新
        ChartAnalysisFactory.getChartStrategyService(entity.getStatisticsType()).updateChart(entity);
        ChartSaveUuidVO chartSaveUuidVO = new ChartSaveUuidVO();
        BeanUtil.copyProperties(entity,chartSaveUuidVO);
        chartSaveUuidList.add(chartSaveUuidVO);
        chartBatchSaveVo.setChartList(chartSaveUuidList);
        return chartBatchSaveVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChartBatchSaveVo salesFunnelPermissionsUpdate(ChartSystemSavePojo chartSystemSavePojo) throws XbbException {
        //"图表中心"的销售漏斗规则修改
        ChartBatchSaveVo chartBatchSaveVo = chartPermissionsUpdate(chartSystemSavePojo);
        //"首页"的销售漏斗规则修改
        salesFunnelHomePermissionsUpdate(chartSystemSavePojo);
        return chartBatchSaveVo;
    }

    private void salesFunnelHomePermissionsUpdate(ChartSystemSavePojo chartSystemSavePojo) throws XbbException {
        String corpid = chartSystemSavePojo.getCorpid();
        Map<String, Object> param = new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("systemCode", SystemCodeEnum.OPPORTUNITY_FUNNEL_HOME.getSystemCode());
        List<ChartEntity> charts = chartModel.findEntitys(param);
        if(CollectionUtils.isNotEmpty(charts) && Objects.nonNull(charts.get(0))){
            //查询该公司的首页销售漏斗
            ChartEntity  salesFunnelHomeChart = charts.get(0);
            ChartEntityEtx requestDTO = chartSystemSavePojo.getChartEntity();
            if(Objects.nonNull(requestDTO)){
                //更新统计规则
                salesFunnelHomeChart.setBelongAttr(requestDTO.getBelongAttr());
                salesFunnelHomeChart.setTimeAttr(requestDTO.getTimeAttr());
                salesFunnelHomeChart.setButtonAttr(requestDTO.getButtonPermissionList());
                chartModel.update(salesFunnelHomeChart);
                return;
            }
        }
        LOG.error("公司{}设置首页销售漏斗统计规则失败",corpid);
    }

    @Override
    public ChartEditVO chartPermissionsGet(ChartEditDTO chartEditDTO) throws XbbException{
        ChartEditVO chartEditVO = new ChartEditVO();
        //已确定statisticsType
        ChartEntity chartEntity = ChartAnalysisFactory.getChartStrategyService(chartEditDTO.getStatisticsType()).getByKey(chartEditDTO.getChartId(), chartEditDTO.getCorpid());
        if(Objects.isNull(chartEntity)){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012);
        }

        // 操作权限
        JSONObject permissions = chartEntity.getPermissions();
        // 自定义pk，permissions用分类的，不用图表的
        if (Objects.equals(chartEntity.getChartType(), ChartTypeEnum.PK_CUSTOM.getCode())) {
            ChartDTO chartDTO = new ChartDTO();
            BeanUtil.copyProperties(chartEditDTO, chartDTO);
            chartDTO.setChartEntity(chartEntity);
            permissions = getChartCategoryPermissions(chartDTO);
        }

        ChartEntityEtx entityEtx = new ChartEntityEtx();
        entityEtx.setPermissions(permissions);
        entityEtx.setEnable(chartEntity.getEnable());
        entityEtx.setPublish(chartEntity.getPublish());
        entityEtx.setChartType(chartEntity.getChartType());
        entityEtx.setCorpid(chartEntity.getCorpid());
        entityEtx.setId(chartEntity.getId());
        entityEtx.setStatisticsType(chartEntity.getStatisticsType());
        chartEditVO.setChart(entityEtx);
        return chartEditVO;
    }

    @Override
    public ChartPermissionAndRuleVO chartPermissionAndRuleGet(ChartPermissionAndRuleDTO chartPermissionAndRuleDTO) throws XbbException{
        ChartPermissionAndRuleVO chartEditVO = new ChartPermissionAndRuleVO();
        ChartEntity chartEntity = chartModel.getByKey(chartPermissionAndRuleDTO.getChartId(), chartPermissionAndRuleDTO.getCorpid());
        ChartEntityEtx entityEtx = new ChartEntityEtx();
        if(Objects.isNull(chartEntity)){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012);
        }
        //操作权限
        entityEtx.setPermissions(chartEntity.getPermissions());
        entityEtx.setEnable(chartEntity.getEnable());
        entityEtx.setPublish(chartEntity.getPublish());
        entityEtx.setChartType(chartEntity.getChartType());
        entityEtx.setCorpid(chartEntity.getCorpid());
        entityEtx.setId(chartEntity.getId());
        entityEtx.setStatisticsType(chartEntity.getStatisticsType());

        //根据formId查询解释
        PaasFormExplainEntity explainEntity = paasFormExplainModel.getByFormId(chartPermissionAndRuleDTO.getFormId(), chartPermissionAndRuleDTO.getCorpid());
        if(Objects.isNull(explainEntity)){
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Integer businessType = explainEntity.getBusinessType();
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explainEntity.getExplains(), null);
        JSONArray timeArrList = new JSONArray();
        JSONArray belongArrList = new JSONArray();
        JSONObject object;
        //旧公司没有设置过，它的 belong_attr 和 time_attr 是空，那么取"创建人"和"预计结束时间"作为默认值
        JSONObject belongAttr = chartEntity.getBelongAttr();
        JSONObject timeAttr = chartEntity.getTimeAttr();
        //图表中心漏斗设置页权限按钮
        List<ChartConfigEnum> configList = new ArrayList<>();
        if(Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode())){
            String chartBelongAttr = Objects.isNull(belongAttr) ? SalesOpportunityEnum.CREATOR_ID.getAttr():belongAttr.getString("attr");
            String chartTimeAttr = Objects.isNull(timeAttr) ? SalesOpportunityEnum.ESTIMATE_END_TIME.getAttr():timeAttr.getString("attr");
            configList.add(ChartConfigEnum.FUNNEL_OPPORTUNITY_LOST_ORDER_BUTTON);
            configList.add(ChartConfigEnum.FUNNEL_OPPORTUNITY_CANCEL_BUTTON);

            //统计规则的字段:创建人，负责人,协同人；创建时间，更新时间，预计结束时间，最后更新时间
            for(String key : explainMap.keySet()){
                //属于统计规则的字段
                if(SalesOpportunityEnum.getSaleFunnelBelongAttrs().contains(key) || SalesOpportunityEnum.getSaleFunnelTimeAttrs().contains(key) ){
                    FieldAttrEntity fieldAttrEntity = explainMap.get(key);
                    //开启的
                    if( Objects.equals(fieldAttrEntity.getIsOpen(), 1)){
                        object = new JSONObject();
                        object.put("attr",key);
                        object.put("isShow",0);//默认下拉框不展示
                        //人员维度
                        if(SalesOpportunityEnum.CREATOR_ID.getAttr().equals(key)){
                            fillJSONArray(key,SalesOpportunityEnum.CREATOR_ID.getAttrName(),object,belongArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(SalesOpportunityEnum.OWNER_ID.getAttr().equals(key)){
                            fillJSONArray(key,SalesOpportunityEnum.OWNER_ID.getAttrName(),object,belongArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(SalesOpportunityEnum.COUSER_ID.getAttr().equals(key)){
                            fillJSONArray(key,SalesOpportunityEnum.COUSER_ID.getAttrName(),object,belongArrList,chartBelongAttr,chartTimeAttr);
                        }
                        //时间维度
                        if(SalesOpportunityEnum.ADD_TIME.getAttr().equals(key)){
                            fillJSONArray(key,SalesOpportunityEnum.ADD_TIME.getAttrName(),object,timeArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(SalesOpportunityEnum.UPDATE_TIME.getAttr().equals(key)){
                            fillJSONArray(key,SalesOpportunityEnum.UPDATE_TIME.getAttrName(),object,timeArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(SalesOpportunityEnum.ANOTHER_ESTIMATE_END_TIME.getAttr().equals(key)){
                            fillJSONArray(key,SalesOpportunityEnum.ANOTHER_ESTIMATE_END_TIME.getAttrName(),object,timeArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(SalesOpportunityEnum.LAST_CONNECT_TIME.getAttr().equals(key)){
                            fillJSONArray(key,SalesOpportunityEnum.LAST_CONNECT_TIME.getAttrName(),object,timeArrList,chartBelongAttr,chartTimeAttr);
                        }
                    }
                }
            }
        } else if(Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode())){
            String chartBelongAttr = Objects.isNull(belongAttr) ? CustomerManagementEnum.CREATOR_ID.getAttr():belongAttr.getString("attr");
            String chartTimeAttr = Objects.isNull(timeAttr) ? CustomerManagementEnum.UPDATE_TIME.getAttr():timeAttr.getString("attr");
            configList.add(ChartConfigEnum.FUNNEL_CUSTOMER_RUN_OFF_BUTTON);

            //统计规则的字段:创建人，负责人,协同人；创建时间，更新时间，最后更新时间
            for(String key : explainMap.keySet()){
                //属于统计规则的字段
                if(CustomerManagementEnum.getCustomerBelongAttrs().contains(key) || CustomerManagementEnum.getCustomerTimeAttrs().contains(key) ){
                    FieldAttrEntity fieldAttrEntity = explainMap.get(key);
                    //开启的
                    if( Objects.equals(fieldAttrEntity.getIsOpen(), 1)){
                        object = new JSONObject();
                        object.put("attr",key);
                        object.put("isShow",0);//默认下拉框不展示
                        //人员维度
                        if(SalesOpportunityEnum.CREATOR_ID.getAttr().equals(key)){
                            fillJSONArray(key,SalesOpportunityEnum.CREATOR_ID.getAttrName(),object,belongArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(CustomerManagementEnum.OWNER_ID.getAttr().equals(key)){
                            fillJSONArray(key,CustomerManagementEnum.OWNER_ID.getAttrName(),object,belongArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(CustomerManagementEnum.COUSERID.getAttr().equals(key)){
                            fillJSONArray(key,CustomerManagementEnum.COUSERID.getAttrName(),object,belongArrList,chartBelongAttr,chartTimeAttr);
                        }
                        //时间维度
                        if(CustomerManagementEnum.ADD_TIME.getAttr().equals(key)){
                            fillJSONArray(key,CustomerManagementEnum.ADD_TIME.getAttrName(),object,timeArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(CustomerManagementEnum.UPDATE_TIME.getAttr().equals(key)){
                            fillJSONArray(key,CustomerManagementEnum.UPDATE_TIME.getAttrName(),object,timeArrList,chartBelongAttr,chartTimeAttr);
                        }
                        if(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr().equals(key)){
                            fillJSONArray(key,CustomerManagementEnum.LAST_CONNECT_TIME.getAttrName(),object,timeArrList,chartBelongAttr,chartTimeAttr);
                        }
                    }
                }
            }
        }
        JSONArray buttonJsonArray = chartEntity.getButtonAttr();
        if (Objects.isNull(buttonJsonArray)){
            buttonJsonArray = new JSONArray();
        }
//        if (!chartEntity.getSystemCode().equals("100_15_02") && !chartEntity.getSystemCode().equals("100_15_03")) {
        List<String> funnelList = Arrays.asList(SystemCodeEnum.CUSTOMER_FUNNEL_CHART.getSystemCode(), SystemCodeEnum.OPPORTUNITY_FUNNEL_CHART.getSystemCode(), SystemCodeEnum.OPPORTUNITY_FUNNEL_HOME.getSystemCode());
        if (funnelList.contains(chartEntity.getSystemCode())) {
            if (CollectionUtils.isEmpty(buttonJsonArray)) {
                for (ChartConfigEnum chartConfigEnum : configList) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("config", chartConfigEnum.getConfig());
                    jsonObject.put("configValue",chartConfigEnum.getConfigValue());
                    buttonJsonArray.add(jsonObject);
                }
            }
            if (CollectionUtils.isNotEmpty(buttonJsonArray)) {
                chartModel.updateButtonAttr(chartEntity.getId(), chartEntity.getCorpid(), buttonJsonArray.toString());
            }
        }
        chartEntity.setButtonAttr(buttonJsonArray);
        chartEditVO.setBelongArrList(belongArrList);
        chartEditVO.setTimeArrList(timeArrList);
        chartEditVO.setChart(entityEtx);
        chartEditVO.setPermissionList(buttonJsonArray);
        return chartEditVO;
    }

    private void fillJSONArray(String attr , String name , JSONObject object , JSONArray jsonArray,String chartBelongAttr ,String chartTimeAttr){
        object.put("name",name);
        if(Objects.equals(attr,chartBelongAttr) || Objects.equals(attr,chartTimeAttr)){
            object.put("isShow",1);
        }
        jsonArray.add(object);

    }


    /**
     * 发布图表到首页
     *
     * @param chartPublishDTO 入参
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartPublishVO
     * @throws XbbException 多个可能的异常
     * @author 徐俊杰
     * @date 2019/5/5 20:36
     * @since v1.0
     */
    @Override
    @Transactional(rollbackFor = XbbException.class)
    public ChartPublishVO chartPublish(ChartPublishDTO chartPublishDTO) throws XbbException {
        //发布或者撤销发布
        Integer publish = chartPublishDTO.getPublish();
        String corpid = chartPublishDTO.getCorpid();
        Long chartId = chartPublishDTO.getChartId();
        //查找要发布的图
        ChartEntity chart;
        if (Objects.equals(chartPublishDTO.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
            chart = chartCustomModel.getByKey(chartId, corpid);
        } else {
            chart = chartModel.getByKey(chartId, corpid);
        }
        if (chart == null) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012, StatisticsServicesErrorCodeEnum.API_ERROR_224012.getMsg());
        }
        //过滤无法发布到首页的图表
        String systemCode = chart.getSystemCode();
        Integer chartType = chart.getChartType();
        if (commonHelp.publishFilter(systemCode, chartType)) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224026, StatisticsServicesErrorCodeEnum.API_ERROR_224026.getMsg());
        }
        //查找首页默认角色的设置
        List<IndexSetEntity> indexSetList = indexSetModel.getCompanyConfig(corpid);
//        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//        param.put("corpid", corpid);
//        param.put("userId", chartPublishDTO.getUserId());
//        param.put("del", DelEnum.NORMAL.getDel());
//        List<IndexSetEntity> indexSetPersonList = indexSetModel.findEntitys(param);
//        if (indexSetPersonList != null && indexSetPersonList.size() > 0) {
//            indexSetList.addAll(indexSetPersonList);
//        }
        if (Objects.equals(ChartPublishEnum.NOT_PUBLISH.getCode(), publish)) {
            //发布
            publish(chartPublishDTO, chart, indexSetList);
        }
        if (Objects.equals(ChartPublishEnum.PUBLISH.getCode(), publish)) {
            //撤销发布
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("userId", chartPublishDTO.getUserId());
            param.put("del", DelEnum.NORMAL.getDel());
            List<IndexSetEntity> indexSetPersonList = indexSetModel.findEntitys(param);
            if (indexSetPersonList != null && indexSetPersonList.size() > 0) {
                indexSetList.addAll(indexSetPersonList);
            }
            cancelPublish(indexSetList, chart);
        }
        return new ChartPublishVO();
    }

    @Override
    public FirstCategoryVO firstCategory(FirstCategoryDTO firstCategoryDTO) throws XbbException {
        ChartCategoryEntity chartCategory = chartCategoryModel.getByKey(firstCategoryDTO.getSecondCategoryId(), firstCategoryDTO.getCorpid());
        if (chartCategory == null) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224024, StatisticsServicesErrorCodeEnum.API_ERROR_224024.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.CHART_CLASSIFY));
        }
        Long firstCategoryId = chartCategory.getParentId();
        if (Objects.equals(firstCategoryId, 0L)) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224028, StatisticsServicesErrorCodeEnum.API_ERROR_224028.getMsg());
        }
        return new FirstCategoryVO(firstCategoryId);
    }

    @Override
    public ChartMirrorInstallVO mirrorInstall(ChartMirrorInstallDTO chartMirrorInstallDTO) throws XbbException {
        List<ChartEntity> chartEntityList = chartMirrorInstallDTO.getChartEntityList();
        List<ChartEntity> chartCustomInsertList = new ArrayList<>();
        List<ChartEntity> chartEntityInsertList = new ArrayList<>();
        for (ChartEntity chartEntity : chartEntityList) {
            if (Objects.equals(chartEntity.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
                if(CollectionsUtil.isNotEmpty(chartEntity.getSlaveSources())){
                    chartEntity.setMuti(0);
                }else{
                    //统计表+图+单表里有团队
                    JSONObject driver = chartEntity.getDriverSources();
                    SlaveSourcePojo driverSource = driver.toJavaObject(SlaveSourcePojo.class);
                    if(ChartTypeEnum.getGroupChartType().contains(chartEntity.getChartType()) && UserTeamEnum.hasTeam(driverSource.getBusinessType())){
                        JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
                        JSONArray colGroupAttr = chartEntity.getColGroupAttr();
                        JSONArray chartClassifyArray = chartEntity.getChartClassify();
                        JSONArray chartSeriesArray = chartEntity.getChartSeries();
                        boolean linkedOrMultiFlag = false;
                        if(CollectionsUtil.isNotEmpty(rowGroupAttr)){
                            linkedOrMultiFlag = isLinkedOrMultiFlag(chartEntity, false, rowGroupAttr);
                        }
                        if(!linkedOrMultiFlag && CollectionsUtil.isNotEmpty(colGroupAttr)){
                            linkedOrMultiFlag = isLinkedOrMultiFlag(chartEntity, false, colGroupAttr);
                        }
                        if(!linkedOrMultiFlag && CollectionsUtil.isNotEmpty(chartClassifyArray)){
                            linkedOrMultiFlag = isLinkedOrMultiFlag(chartEntity, false, chartClassifyArray);
                        }
                        if(!linkedOrMultiFlag && CollectionsUtil.isNotEmpty(chartSeriesArray)){
                            isLinkedOrMultiFlag(chartEntity, false, chartSeriesArray);
                        }
                    }
                }
                chartCustomInsertList.add(chartEntity);
                customHelp.setSourcePojo(chartEntity);
            } else {
                chartEntityInsertList.add(chartEntity);
            }
        }
        if (chartEntityInsertList.size() > 0) {
            chartModel.insertBatch(chartEntityInsertList);
        }
        if (chartCustomInsertList.size() > 0) {
            chartCustomModel.insertBatch(chartCustomInsertList);
        }
        for (ChartEntity chartEntity : chartCustomInsertList) {
            JSONArray slaveSources = chartEntity.getSlaveSources();
            //多表的关联
            if(!slaveSources.isEmpty()){
                if(Objects.equals(0,chartEntity.getSingle()) || Objects.equals(1, chartEntity.getSingle())){
                    ChartEditDTO chartEditDTO = new ChartEditDTO();
                    chartEditDTO.setCorpid(chartMirrorInstallDTO.getCorpid());
                    chartEditDTO.setChartId(chartEntity.getId());
                    dataWarehouseService.initData(chartEditDTO);
                }
            }
        }
        ChartMirrorInstallVO chartMirrorInstallVO = new ChartMirrorInstallVO();
        chartMirrorInstallVO.setChartEntityList(chartEntityList);
        return chartMirrorInstallVO;
    }

    /**
     * （1）先获取出子分类ids：二级分类要按照sort值排序，保证父分类下的子分类的图表按顺序排列
     * （2）（各个子分类的）图表需要按照同分类（同二级分类）的放置到一起
     * @param chartMobileListDTO 入参
     * @param categoryId 分类id
     * @param pkTypeMap 图表id--pk类型（ChartConstant内的PK_NO、PK_USER、PK_DEP、PK_DEP_USER）
     * @param chartMap 图表参数map
     * @return java.util.List<com.xbongbong.pro.domain.entity.ext.ChartEntityEtx>
     * @throws XbbException
     * @author zcp
     * @date 2019/2/1 9:33
     * @since v1.0
     * @version v1.0
     */
    private List<ChartEntityEtx> getChartsByCategory4App(ChartMobileListDTO chartMobileListDTO, Long categoryId, Map<Long, Integer> pkTypeMap, Map<String, Object> chartMap) throws XbbException {
        List<ChartEntityEtx> chartList = new ArrayList<>();
        String corpid = chartMobileListDTO.getCorpid();
        ChartCategoryEntity categoryEntity = chartCategoryModel.getByKey(categoryId, corpid);
        if (categoryEntity == null) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224024, StatisticsServicesErrorCodeEnum.API_ERROR_224024.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.CHART_CLASSIFY));
        }
        List<Long> categoryIdIn = new ArrayList<>();
        categoryIdIn.add(categoryEntity.getId());
        Integer categoryType = categoryEntity.getType();
        //默认非pk
        int pkFlag = getPkFlag(categoryType);
        chartMap.put("categoryIdIn", categoryIdIn);
        chartMap.put("orderByStr", "sort DESC, id ASC");
        @SuppressWarnings("unchecked")
        List<Integer> chartTypeList = (List<Integer>) chartMap.get("chartTypeIn");
        //仪表盘下选择目标完成情况表，移动端兼容展示
        if (Objects.equals(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), chartMobileListDTO.getStatisticsType())) {
            chartTypeList.add(ChartTypeEnum.PERFORMANCE_TABLE.getCode());
        } else {
            // 查询系统业绩目标，只需要二级分类
            Iterator<Integer> iterator = chartTypeList.iterator();
            while (iterator.hasNext()) {
                Integer next = iterator.next();
                if (Objects.equals(next, ChartTypeEnum.PERFORMANCE.getCode())) {
                    iterator.remove();
                    break;
                }
            }
        }
        chartMap.put("chartTypeIn", chartTypeList);
        List<ChartEntity> list = chartModel.findEntitys(chartMap);
        //自定义图表和系统图表可能会出现在同一个大分组里，手机端请求的是大分组
        list.addAll(chartCustomModel.findEntitys(chartMap));
        /*
         分类id---该分类下的图表数组
         把相同分类的图表放到一起，然后这些图表按照分类的顺序进行批量放置到一起
         */
        Map<Long, List<ChartEntityEtx>> chartEntityEtxListMap = new HashMap<>(list.size());
        //非收藏图表
        boolean searchFlag = !StringUtil.isEmpty(chartMobileListDTO.getNameLike());
        for (ChartEntity chartEntity : list) {
            //当搜索时，不搜索到业绩目标移动端（移动端业绩目标是特殊图表：会默认展示所有目标的环图，有整个分组筛选，无法在搜索结果内统一展示）
            if (searchFlag && Objects.equals(ChartTypeEnum.PERFORMANCE_GAUGES.getCode(), chartEntity.getChartType())) {
                continue;
            }
            JSONObject explains = chartEntity.getExplains();
            if(explains != null ) {
                ExplainsPojo explainsPojo = explains.toJavaObject(ExplainsPojo.class);
                Integer appHide = explainsPojo.getAppHide();
                boolean containFlag = false;
                if(explainsPojo.getAppPosition()!= null){
                    containFlag = explainsPojo.getAppPosition().keySet().contains(categoryId.toString());
                }
                //不为null且等于0时显示
                if (appHide != null && appHide == 0 && containFlag) {
                    continue;
                }
            }
            List<Long> cidList = chartEntity.getCategory().toJavaList(Long.class);
            for (Long cid : cidList) {
                if (!categoryIdIn.contains(cid)) {
                    continue;
                }
                List<ChartEntityEtx> etxList = chartEntityEtxListMap.get(cid);
                if (null == etxList) {
                    etxList = new ArrayList<>();
                }
                Integer pkType = pkTypeMap.get(chartEntity.getId());
                //pk类型一致，或者部门员工pk都收藏了
                boolean favoriteFlag = pkType != null && (pkFlag == pkType || ChartConstant.PK_DEP_USER == pkType);
                int favorite = favoriteFlag ? 1 : 0;
                ChartEntityEtx chartEntityEtx = getChartEntityEtx(chartEntity);
                chartEntityEtx.setFavorite(favorite);
                //设置单个系统图表的search
                if (StatisticsTypeEnum.SYSTEM_STATISTIC.getCode() == chartEntityEtx.getStatisticsType()) {
                    setChartSearch(chartEntityEtx);
                    //部门pk和员工pk的search特殊处理
                    JSONArray search = handlePkSearch(pkFlag, chartEntityEtx);
                } else if (Objects.equals(ChartTypeEnum.PK_CUSTOM.getCode(), chartEntity.getChartType())) {
                    // 自定义pk特殊处理
                    JSONArray search = new JSONArray();
                    // 默认置入这两个筛选
                    search.add(FilterConditionEnum.TIME_ALL.getCode());
                    search.add(FilterConditionEnum.ORGANIZATION_ALL.getCode());
                    chartEntityEtx.setSearch(search);
                    //设置hasSearch属性
                    chartEntityEtx.setHasSearch(ChartConstant.HAS_SEARCH);
                }
                etxList.add(chartEntityEtx);
                chartEntityEtxListMap.put(cid, etxList);
            }
        }
        //因为此时categoryIdIn内的分类id是按照分类排过顺序的
        for (Long cid : categoryIdIn) {
            List<ChartEntityEtx> etxList = chartEntityEtxListMap.get(cid);
            if (etxList == null) {
                continue;
            }
            chartList.addAll(etxList);
        }
        return chartList;
    }

    /**
     * 部门pk和员工pk的search特殊处理
     * @param pkFlag
     * @param chartEntityEtx
     * @return
     */
    private JSONArray handlePkSearch(int pkFlag, ChartEntityEtx chartEntityEtx) {
        //比较分类类型
        JSONArray search = chartEntityEtx.getSearch();
        if (ChartConstant.PK_DEP == pkFlag && Objects.nonNull(search)) {
            search.remove(FilterConditionEnum.ORGANIZATION_ALL.getCode());
        }
        return search;
    }


    /**
     * 设置控件返回值
     * @param attrConditionVO   载体
     * @param aggsTypeClassList  枚举列表
     * @param widgetName   控件名称
     * @param widgetType  控件类型
     */
    private void attrConditionVO(AttrConditionVO attrConditionVO, List<AggsTypeClass> aggsTypeClassList, String widgetName, String widgetType) {
        ConditionPojo conditionPojo = new ConditionPojo();
        conditionPojo.setWidgetName(widgetName);
        conditionPojo.setWidgetType(widgetType);
        List<WidgetSelectPojo> selectList = new ArrayList<>();
        for (AggsTypeClass aggsTypeClass : aggsTypeClassList) {
            WidgetSelectPojo widgetSelectPojo = new WidgetSelectPojo();
            widgetSelectPojo.setKey(aggsTypeClass.getAlias());
            widgetSelectPojo.setValue(aggsTypeClass.getName());
            selectList.add(widgetSelectPojo);
        }
        conditionPojo.setSelectList(selectList);
        attrConditionVO.addConditionList(conditionPojo);
    }


    /**
     * 封装ChartEntityEtx
     * @param chartEntity 图表实体
     * @return com.xbongbong.pro.domain.entity.ext.ChartEntityEtx
     * @author zcp
     * @date 2019/1/30 9:25
     * @since v1.0
     * @version v1.0
     */
    private ChartEntityEtx getChartEntityEtx(ChartEntity chartEntity) {
        ChartEntityEtx chartEntityEtx = new ChartEntityEtx();
        BeanUtil.copyProperties(chartEntity,chartEntityEtx);
        //拼category的alias供前端判断
        ChartCategoryEntity chartCategoryEntity = chartCategoryModel.getByKey(chartEntity.getCategory().getLong(0), chartEntity.getCorpid());
        chartEntityEtx.setAlias(chartCategoryEntity.getAlias());
        //为了返回前端name_en不为null
        String name = chartEntity.getName();
        String nameEn = chartEntity.getNameEn();
        if (StringUtil.isEmpty(nameEn)){
            chartEntityEtx.setNameEn(name);
        }
        JSONArray search = chartEntity.getSearch();
        if(search!=null && !search.isEmpty()){
            chartEntityEtx.setHasSearch(1);
        }
        JSONObject explains = chartEntity.getExplains();
        if(explains != null ){
            ExplainsPojo explainsPojo = explains.toJavaObject(ExplainsPojo.class);
            JSONObject frozeColum = explainsPojo.getFrozeColum();
            if (frozeColum == null) {
                return chartEntityEtx;
            }
            Long formId = frozeColum.getLong(FieldAttrConstant.FORMID);
            String attr = frozeColum.getString(FieldAttrConstant.ATTR);
            chartEntityEtx.setFrozeColumDone(explainsPojo.getFrozeColumDone());
            chartEntityEtx.setFrozeRowDone(explainsPojo.getFrozeRowDone());
            chartEntityEtx.setMap(explainsPojo.getMap());
            chartEntityEtx.setFunnel(explainsPojo.getFunnel());
            chartEntityEtx.setMapDistrict(explainsPojo.getMapDistrict());
            //下面这段代码绝对是有问题的，首先单表是没有originalAttr，其次多表的attr不管是display里面的还是froze里面的都是经过规则转化之后的，
            // 但是原先逻辑是用转化之后的attr和未转化的originalAttr去进行比较，肯定有问题，所以我这边先修改掉，后面有场景再说
            chartEntity.getDisplayAttr().forEach(item -> {
                JSONObject jsonObject = (JSONObject) item;
                if (Objects.equals(formId, jsonObject.getLong(FieldAttrConstant.FORMID)) && Objects.equals(attr, jsonObject.getString(FieldAttrConstant.ATTR))) {
                    frozeColum.put(FieldAttrConstant.ATTR, jsonObject.getString(FieldAttrConstant.ATTR));
                }
            });
            chartEntityEtx.setFrozeColum(frozeColum);
        }
        return chartEntityEtx;
    }
    /**
     * 设置是否是图和表
     *
     * @param chartEntityEtx 图表实体扩展类
     * @author 徐俊杰
     * @date 2019/2/15 14:39
     * @since v1.0
     */
    private void setIfChartAndTable(ChartEntityEtx chartEntityEtx) {
        JSONArray showTypesArr = chartEntityEtx.getShowTypes();
        List<Integer> showTypes = showTypesArr == null ? new ArrayList<>() : showTypesArr.toJavaList(Integer.class);
        //判断是否是表格
        Integer tableCode = ChartTypeEnum.TABLE.getCode();
        if (showTypes.contains(tableCode)) {
            chartEntityEtx.setIfTable(true);
            showTypes.remove(tableCode);
        } else {
            chartEntityEtx.setIfTable(false);
        }
        //判断是否是图
        List<Integer> systemTypes = ChartTypeEnum.getSystemChartType();
        if (0 != showTypes.size() && systemTypes.containsAll(showTypes)) {
            chartEntityEtx.setIfChart(true);
        } else {
            chartEntityEtx.setIfChart(false);
        }
    }
    /**
     * 设置单个系统图表的search
     *
     * @param chartEntityEtx 图表实体扩展
     * @author 徐俊杰
     * @date 2019/3/25 14:36
     * @since v1.0
     */
    private void setChartSearch(ChartEntityEtx chartEntityEtx) {
        //从SystemCodeEnum中读出枚举值，设置search
        String systemCode = chartEntityEtx.getSystemCode();
        SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(systemCode);
        List<Integer> filterConditionList = systemCodeEnum.getFilterConditionList();
        JSONArray search = JSONArray.parseArray(JSON.toJSONString(filterConditionList));
        chartEntityEtx.setSearch(search);
        //设置hasSearch属性
        chartEntityEtx.setHasSearch(ChartConstant.HAS_SEARCH);
    }

    /**
     * 根据分类类型获取pk类型，默认为非pk
     * @param categoryType 分类类型
     * @return int ChartConstant内的PK_NO、PK_USER、PK_DEP、PK_DEP_USER
     * @author zcp
     * @date 2019/3/26 11:39
     * @since v1.0
     * @version v1.0
     */
    private int getPkFlag(Integer categoryType) {
        //默认为非pk
        int pkFlag = ChartConstant.PK_NO;
        if (categoryType == null) {
            return pkFlag;
        }
        if (ChartCategoryTypeEnum.PK_USER.getCode() == categoryType) {
            pkFlag = ChartConstant.PK_USER;
        } else if (ChartCategoryTypeEnum.PK_DEP.getCode() == categoryType) {
            pkFlag = ChartConstant.PK_DEP;
        }
        return pkFlag;
    }


    @Override
    public CustomChartDeleteVO deleteCustomChart(CustomChartDeleteDTO chartDeleteDTO) throws XbbException {
        CustomChartDeleteVO customChartDeleteVO = new CustomChartDeleteVO();
        try {
            String corpid = chartDeleteDTO.getCorpid();
            Long chartId = chartDeleteDTO.getChartId();
            ChartEntity chartEntity =  chartCustomModel.getByKey(chartId, corpid);
            if (Objects.isNull(chartEntity)) {
                throw  new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012);
            }
            List<Integer> chartTypeList = ChartTypeEnum.getCustomChartType();
            if (!chartTypeList.contains(chartEntity.getChartType())) {
                throw  new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224013);
            }
            chartCustomModel.deleteByKey(chartId, corpid);
            String logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_DELETE_CHART);
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
            String userName = chartDeleteDTO.getLoginUserName();
            String memo = String.format(logMemoUpdateTemplate, userName ,chartEntity.getName());
            mongoLogHelp.buildLog(corpid, chartDeleteDTO.getUserId(), userName, OperateModuleTypeEnum.CHART, operateTypeEnum, chartEntity.getId().toString(), chartEntity.getName(),
                    memo, chartDeleteDTO.getHttpHeader());

        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("删除自定义图表失败：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return customChartDeleteVO;
    }

    @Override
    @Transactional(rollbackFor = XbbException.class)
    public ChartSaveVO chartUpdateDashboard(ChartSavePositionDTO chartSavePositionDTO) throws XbbException {
        List<ChartEntityEtx> chartList = chartSavePositionDTO.getChartList();
        List<ChartCategoryTextEntity> textList = chartSavePositionDTO.getTextList();
        Long categoryId = chartSavePositionDTO.getCategoryId();
        if (chartList.size() == 0) {
            return new ChartSaveVO();
        }
        String corpid = chartSavePositionDTO.getCorpid();
        List<ChartEntity> systemInsertList = new ArrayList<>();
        List<ChartEntity> customInsertList = new ArrayList<>();
        List<ChartEntityEtx> insertList = new ArrayList<>();
        Set<Long> delIdList = new HashSet<>();
        // 查出现有的次仪表盘下的chartId集合
        HashMap<String,Object> chartParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        chartParam.put("corpid",corpid);
        chartParam.put("del",DelEnum.NORMAL);
        chartParam.put("categoryId",chartSavePositionDTO.getCategoryId());
        chartParam.put("columns","id");
        List<ChartEntity> customList = chartCustomModel.findEntitys(chartParam);
        List<ChartEntity> systemList = chartModel.findEntitys(chartParam);
        //自定义、系统图表可能会id冲突
        List<Long> chartCustomIds = customList.stream().map(e ->e.getId()).collect(Collectors.toList());
        List<Long> chartSysIds = systemList.stream().map(e ->e.getId()).collect(Collectors.toList());
        chartList.forEach(entity -> {
            Long id = entity.getId();
            Integer del = entity.getDel();
            Integer statisticsType = entity.getStatisticsType();
            boolean flagSys = Objects.equals(statisticsType, StatisticsTypeEnum.SYSTEM_STATISTIC.getCode());
            ChartEntity chartEntity = new ChartEntity();
            chartEntity.setId(id);
            JSONArray category = entity.getCategory();
            if (del != null && Objects.equals(del, DelEnum.DELETE.getDel())) {
                if (category.size() == 1) {
                    chartEntity.setDel(DelEnum.DELETE.getDel());
                    delIdList.add(id);
                } else if(category.size() > 1){
                    category.removeIf(obj -> Objects.equals(obj.toString(), categoryId.toString()));
                    chartEntity.setExplains(entity.getExplains());
                }
                if (flagSys && CollectionUtils.isNotEmpty(chartSysIds)) {
                    chartSysIds.remove(id);
                } else if (!flagSys && CollectionUtils.isNotEmpty(chartCustomIds)) {
                    chartCustomIds.remove(id);
                }
            } else {
                if (null != id && Objects.equals(del, DelEnum.NORMAL.getDel())){
                    if (flagSys && !chartSysIds.contains(id)) {
                        chartSysIds.add(id);
                    } else if (!flagSys && !chartCustomIds.contains(id)) {
                        chartCustomIds.add(id);
                    }
                }
                chartEntity.setExplains(entity.getExplains());
            }
            chartEntity.setCategory(category);
            if (flagSys) {
                systemInsertList.add(chartEntity);
            } else {
                customInsertList.add(chartEntity);
            }
            if (null == id){
                //联动设置置空
                entity.setChartLinkage(null);
                insertList.add(entity);
            }
        });

        int totalSize = chartCustomIds.size() + chartSysIds.size() + insertList.size();
        //数量控制
        // 判断该公司是否在图表限制表里面
        Integer limitNum = commonHelp.getChartLimit(corpid,ChartLimitTypeEnum.CHART_NUM_LIMIT.getAlias());
        //TODO 应该判断del
        if (totalSize > limitNum) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224080, StatisticsServicesErrorCodeEnum.API_ERROR_224080.getMsg(), limitNum);
        }
        if (delIdList.size() > 0) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID, corpid);
            param.put(StringConstant.IDIN, delIdList);
            List<ChartEntity> delChartList = chartCustomModel.findEntitys(param);
            for (ChartEntity chartEntity : delChartList) {
                boolean isSingle = EsUtil.getSingle(chartEntity);
                //多表情况下处理关联表
                if (!isSingle) {
                    decrCorrection(chartEntity);
                }
            }
            // 删除表的时候删除预警
            dataWarningModel.deleteBatch(corpid,new ArrayList<>(delIdList));

        }
        if (chartList.size() > 0) {
            try {
                if (customInsertList.size() > 0) {
                    chartCustomModel.updateBatch(customInsertList, corpid);
                }
                if (systemInsertList.size() > 0) {
                    chartModel.updateBatch(systemInsertList, corpid);
                }
            } catch (Exception e) {
                LOG.error("chartSavePosition updateBatch error", e);
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224086);
            }
        }
        if (insertList.size()>0){
            ChartSavePojo chartSavePojo = new ChartSavePojo();
            BeanUtils.copyProperties(chartSavePositionDTO,chartSavePojo);
            List<ChartEntityEtx> insertExtList = new ArrayList<>();
            Locale locale = LocaleContextHolder.getLocale();
            insertList.forEach(item ->{
                if (Objects.equals(locale.getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE)){
                    item.setNameEn(item.getName());
                    item.setName(item.getNameEn());
                }
                insertExtList.add(item);
            });
            chartSavePojo.setChartList(insertExtList);
            try {
                chartSave(chartSavePojo);
            } catch (XbbException e) {
                throw  e;
            } catch (Exception e) {
                LOG.error("",e);
                throw  new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224087);
            }
        }
        if (CollectionUtils.isNotEmpty(textList)){
            try {
                //更新文本组件的全局样式
                if (!textList.isEmpty()){
                    ChartCategoryTextUpdateBatchDTO chartCategoryTextSaveDTO = new ChartCategoryTextUpdateBatchDTO();
                    chartCategoryTextSaveDTO.setTextList(textList);
                    chartCategoryTextSaveDTO.setCorpid(corpid);
                    chartCategoryTextSaveDTO.setCategoryId(categoryId);
                    chartCategoryTextService.updateBatch(chartCategoryTextSaveDTO);
                }
            }catch (Exception e) {
                LOG.error("chartSavePosition updateBatch error", e);
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
            }
        }
        return new ChartSaveVO();
    }

    @Override
    @Transactional(rollbackFor = XbbException.class)
    public ChartSaveVO chartUpdateStyle(ChartSaveStyleDTO chartSaveStyleDTO) throws XbbException {
        List<ChartEntity> chartList = chartSaveStyleDTO.getChartList();
        Long categoryId = chartSaveStyleDTO.getCategoryId();
        if (chartList.size() == 0) {
            return new ChartSaveVO();
        }
        String corpid = chartSaveStyleDTO.getCorpid();
        List<ChartEntity> systemInsertList = new ArrayList<>();
        List<ChartEntity> customInsertList = new ArrayList<>();
        chartList.forEach(entity -> {
            if (Objects.equals(entity.getStatisticsType(), StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())) {
                systemInsertList.add(entity);
            } else {
                customInsertList.add(entity);
            }
        });
        JSONObject globalStyleOption = chartSaveStyleDTO.getGlobalStyleOption();
        List<ChartCategorySearchEntity> searchList = chartSaveStyleDTO.getSearchList();
        List<ChartCategoryTextEntity> textList = chartSaveStyleDTO.getTextList();
        if (chartList.size() > 0) {
            try {
                if (customInsertList.size() > 0) {
                    chartCustomModel.updateBatch(customInsertList, corpid);
                }
                if (systemInsertList.size() > 0) {
                    chartModel.updateBatch(systemInsertList, corpid);
                }
                //更新仪表盘的全局样式
                if (Objects.nonNull(globalStyleOption)){
                    ChartCategoryEntity chartCategoryEntity = new ChartCategoryEntity();
                    chartCategoryEntity.setCorpid(corpid);
                    chartCategoryEntity.setId(categoryId);
                    chartCategoryEntity.setGlobalStyleOption(globalStyleOption);
                    chartCategoryModel.updateGlobalStyle(chartCategoryEntity);
                }
                //更新查询条件的全局样式
                if (!searchList.isEmpty()){
                    chartCategorySearchModel.updateBatch(searchList, corpid);
                }
                //更新文本组件的全局样式
                if (!textList.isEmpty()){
                    ChartCategoryTextUpdateBatchDTO chartCategoryTextSaveDTO = new ChartCategoryTextUpdateBatchDTO();
                    chartCategoryTextSaveDTO.setTextList(textList);
                    chartCategoryTextSaveDTO.setCorpid(corpid);
                    chartCategoryTextSaveDTO.setCategoryId(categoryId);
                    chartCategoryTextService.updateBatch(chartCategoryTextSaveDTO);
                }
            } catch (Exception e) {
                LOG.error("chartSaveDisplay updateBatch error", e);
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
            }
        }
        return new ChartSaveVO();
    }
    /**
     * 系统表更新默认排序设置
     * @param chartSavePositionDTO
     * @return
     * @throws XbbException
     */
    @Override
    public ChartSaveVO chartUpdateSort(ChartSavePositionDTO chartSavePositionDTO) throws XbbException {
        List<ChartEntityEtx> chartList = chartSavePositionDTO.getChartList();
        List<ChartEntity> systemInsertList = new ArrayList<>();
        List<ChartEntity> customInsertList = new ArrayList<>();
        String corpid = chartSavePositionDTO.getCorpid();
        chartList.forEach(entityEtx -> {
            ChartEntity entity = new ChartEntity();
            BeanUtil.copyProperties(entityEtx, entity);
            if (Objects.equals(entity.getStatisticsType(), StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())) {
                systemInsertList.add(entity);
            } else {
                customInsertList.add(entity);
            }
        });

        if (chartList.size() > 0) {
            try {
                if (customInsertList.size() > 0) {
                    chartCustomModel.updateBatch(customInsertList, corpid);
                }
                if (systemInsertList.size() > 0) {
                    chartModel.updateBatch(systemInsertList, corpid);
                }
            } catch (Exception e) {
                LOG.error("chartSavePosition updateBatch error", e);
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
            }
        }
        return new ChartSaveVO();
    }

    /**
     * 发送到首页
     *
     * @param chartPublishDTO 入参
     * @param chart 要发送的图表
     * @param indexSetList 首页看板配置列表
     * @throws XbbException 入参异常
     * @author 徐俊杰
     * @date 2019/5/5 20:10
     * @since v1.0
     */
    private void publish(ChartPublishDTO chartPublishDTO, ChartEntity chart, List<IndexSetEntity> indexSetList) throws XbbException {
        String corpid = chartPublishDTO.getCorpid();
        Long chartId = chartPublishDTO.getChartId();
        Integer head = chartPublishDTO.getHead();
        Integer statisticsType = chartPublishDTO.getStatisticsType();
        if (head == null) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224050);
        }
        //包装发布的图的数据
        IndexSetDataPojo publishChart = new IndexSetDataPojo();
        //传入chartId，由type区分
        publishChart.setChartCategoryId(chartId);
        publishChart.setChartCategoryType(ChartConstant.CHART_CATEGORY_TYPE_CHART);
        publishChart.setEnable(chart.getEnable());
        publishChart.setShowType(chart.getChartType());
        //处理图表分类
        List<Long> cidList = chart.getCategory().toJavaList(Long.class);
        publishChart.setSecondCategoryId(cidList.get(0));
        publishChart.setStatisticsType(statisticsType);
        // 发布的时候将那些已经发布但是删除的图表移除一下，不要占着发布的名额（自定义图表才会删除）
        List<Long> chartIds = new ArrayList<>();
        List<ChartEntity> chartEntityList = new ArrayList<>();
        //遍历设置列表
        for (IndexSetEntity indexSet : indexSetList) {
            Integer boardType = indexSet.getBoardType();
            //跳过网页右侧分类,以及移动端专注模式下的右侧（工作tab）
            if (Objects.equals(ChartCategoryTypeEnum.WEB_INDEX_RIGHT.getCode(), boardType) || Objects.equals(BoardTypeEnum.FOCUS_DINGTALK_WORK.getCode(), boardType)) {
                continue;
            }
            JSONArray contentData = indexSet.getContentData();
            List<IndexSetDataPojo> indexSetDataPojos = contentData.toJavaList(IndexSetDataPojo.class);
            //已经发送到首页图表的数量
            Integer indexChartNum = BasicConstant.ZERO;
            Iterator<IndexSetDataPojo> iterator = indexSetDataPojos.iterator();
            // 用temp防止两端数据不一样，脏数据
            List<Long> tempChartIds = new ArrayList<>();
            //判断是否已经发送到了首页
            while (iterator.hasNext()) {
                IndexSetDataPojo pojo = iterator.next();
                Integer type = pojo.getChartCategoryType();
                Integer pojoStatisticsType = pojo.getStatisticsType();
                Long pojoChartId = pojo.getChartCategoryId();
                boolean sameType = Objects.equals(ChartConstant.CHART_CATEGORY_TYPE_CHART, type);
                boolean sameChart = Objects.equals(chartId, pojoChartId);
                boolean sameStatisticsType = Objects.equals(statisticsType, pojoStatisticsType);
                if (sameType && sameChart && sameStatisticsType) {
                    //可能需要更新在尾部或在顶部，故remove而不是replace
                    iterator.remove();
                }
                //判断是否是发送到首页的图表
                if (sameType) {
                    indexChartNum += BasicConstant.ONE;
                    if (Objects.equals(statisticsType,StatisticsTypeEnum.CUSTOM_STATISTIC.getCode()) && !chartIds.contains(pojoChartId)){
                        tempChartIds.add(pojoChartId);
                    }
                }
            }
            if (CollectionsUtil.isNotEmpty(tempChartIds)){
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put("corpid", corpid);
                param.put("idIn", tempChartIds);
                param.put("publish",ChartPublishEnum.PUBLISH.getCode());
                param.put("del", DelEnum.DELETE.getDel());
                List<ChartEntity> tempChartEntityList = chartCustomModel.findEntitys(param);
                if (CollectionsUtil.isNotEmpty(tempChartEntityList)){
                    tempChartIds = tempChartEntityList.stream().map(e ->e.getId()).collect(Collectors.toList());
                    chartEntityList.addAll(tempChartEntityList);
                    chartIds.addAll(tempChartIds);
                }
            }
            if (CollectionsUtil.isNotEmpty(chartIds)){
                int deleteNum = 0;
                iterator = indexSetDataPojos.iterator();
                while (iterator.hasNext()) {
                    IndexSetDataPojo pojo = iterator.next();
                    Integer type = pojo.getChartCategoryType();
                    Integer pojoStatisticsType = pojo.getStatisticsType();
                    Long pojoChartId = pojo.getChartCategoryId();
                    if(Objects.equals(ChartConstant.CHART_CATEGORY_TYPE_CHART, type) && Objects.equals(pojoStatisticsType,StatisticsTypeEnum.CUSTOM_STATISTIC.getCode()) && chartIds.contains(pojoChartId)){
                        iterator.remove();
                        deleteNum ++;
                    }
                }
                indexChartNum -= deleteNum;
            }
            //判断发送到首页的图表数量是否大于20
            if (indexChartNum >= ChartConstant.INDEX_CHART_MAX_NUM) {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224029, String.format(StatisticsServicesErrorCodeEnum.API_ERROR_224029.getMsg(), ChartConstant.INDEX_CHART_MAX_NUM));
            }

            //设置sort值和排序
            //发布到头部
            if (Objects.equals(ChartConstant.PUBLISH_HEAD, head)) {
                //从数据库中取得的值是有序的，因此只要获取第一个就可以拿到sort的最大值
                IndexSetDataPojo first = indexSetDataPojos.get(0);
                Integer firstSort = first.getSort();
                Integer publishChartSort = firstSort + BasicConstant.ONE;
                publishChart.setSort(publishChartSort);
            }
            //发布到尾部
            if (Objects.equals(ChartConstant.PUBLISH_TAIL, head)) {
                //将首页已有的图表sort + 1
                for (IndexSetDataPojo pojo : indexSetDataPojos) {
                    pojo.setSort(pojo.getSort() + BasicConstant.ONE);
                }
                //将发布的图设置为尾部
                publishChart.setSort(ChartConstant.TAIL_SORT);
            }
            indexSetDataPojos.add(publishChart);
            //进行排序
            indexSetDataPojos.sort((pojo1, pojo2) -> pojo2.getSort() - pojo1.getSort());
            contentData = JSONArray.parseArray(JSON.toJSONString(indexSetDataPojos));
            indexSet.setUpdateTime(DateTimeUtil.getInt());
            indexSet.setContentData(contentData);
        }
        //批量更新
        indexSetModel.updateBatch(indexSetList, corpid);
        //更新该图表的是否在首页的状态
        chart.setPublish(ChartPublishEnum.PUBLISH.getCode());
        //name和nameEn的值交换
        commonHelp.exchangeChartNameAndNameEn(chart);
        if (Objects.equals(chart.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
            chartCustomModel.save(chart);
        } else {
            chartModel.save(chart);
        }
    }

    /**
     * 撤销发布
     *
     * @param indexSetList 首页看板配置列表
     * @param chart 图表
     * @throws XbbException 首页看板相关异常
     * @author 徐俊杰
     * @date 2019/5/5 20:32
     * @since v1.0
     */
    private void cancelPublish(List<IndexSetEntity> indexSetList, ChartEntity chart) throws XbbException {
        Long chartId = chart.getId();
        String corpid = chart.getCorpid();
        for (IndexSetEntity indexSet : indexSetList) {
            Integer boardType = indexSet.getBoardType();
            //跳过网页右侧分类,以及移动端专注模式下的右侧（工作tab）
            if (Objects.equals(ChartCategoryTypeEnum.WEB_INDEX_RIGHT.getCode(), boardType) || Objects.equals(BoardTypeEnum.FOCUS_DINGTALK_WORK.getCode(), boardType)) {
                continue;
            }
            JSONArray contentData = indexSet.getContentData();
            List<IndexSetDataPojo> indexSetDataPojos = contentData.toJavaList(IndexSetDataPojo.class);
            //遍历获取（在首页）需要删除的图
            IndexSetDataPojo deletePojo = null;
            for (IndexSetDataPojo pojo : indexSetDataPojos) {
                //根据chartId和type确认是当前图表
                Long indexChartId = pojo.getChartCategoryId();
                Integer type = pojo.getChartCategoryType();
                if (indexChartId == null || type == null) {
                    throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224051);
                }
                if (Objects.equals(chartId, indexChartId) && Objects.equals(type, ChartConstant.CHART_CATEGORY_TYPE_CHART)) {
                    deletePojo = pojo;
                    break;
                }
            }
            if (deletePojo == null) {
                continue;
            }
            //移除需要删除的图
            indexSetDataPojos.remove(deletePojo);
            Integer deletePojoSort = deletePojo.getSort();
            //遍历首页的图，将（sort大于被删除图sort）sort值减一
            for (IndexSetDataPojo pojo : indexSetDataPojos) {
                Integer sort = pojo.getSort();
                if (sort > deletePojoSort) {
                    sort = sort - BasicConstant.ONE;
                    pojo.setSort(sort);
                }
            }
            contentData = JSONArray.parseArray(JSON.toJSONString(indexSetDataPojos));
            indexSet.setUpdateTime(DateTimeUtil.getInt());
            indexSet.setContentData(contentData);
        }
        indexSetModel.updateBatch(indexSetList, corpid);
        //name和nameEn的值交换
        commonHelp.exchangeChartNameAndNameEn(chart);
        chart.setPublish(ChartPublishEnum.NOT_PUBLISH.getCode());
        if (Objects.equals(chart.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
            chartCustomModel.save(chart);
        } else {
            chartModel.save(chart);
        }
    }
    /**
     * 设置copy字段
     * @param entity
     * @param editAble
     */
    private void setCopyAttr(ChartEntity entity, boolean editAble) {
        JSONObject driverSources = entity.getDriverSources();
        JSONArray slaveSources = entity.getSlaveSources();
        if(!driverSources.isEmpty()){
            SlaveSourcePojo driverSourcePojo = driverSources.toJavaObject(SlaveSourcePojo.class);
            if(editAble){
                if( !Objects.equals(BiConstant.DEFAULT_ATTR,driverSourcePojo.getLinkAttr())){
                    driverSourcePojo.setLinkAttrCopy(driverSourcePojo.getLinkAttr());
                    driverSourcePojo.setLinkAttrBCopy(driverSourcePojo.getLinkAttrB());
                    driverSourcePojo.setLinkAttrCCopy(driverSourcePojo.getLinkAttrC());
                    driverSourcePojo.setLinkAttrDCopy(driverSourcePojo.getLinkAttrD());
                    driverSourcePojo.setLinkAttrECopy(driverSourcePojo.getLinkAttrE());
                }
            }else {
                driverSourcePojo.setLinkAttrCopy(driverSourcePojo.getLinkAttr());
                driverSourcePojo.setLinkAttrBCopy(driverSourcePojo.getLinkAttrB());
                driverSourcePojo.setLinkAttrCCopy(driverSourcePojo.getLinkAttrC());
                driverSourcePojo.setLinkAttrDCopy(driverSourcePojo.getLinkAttrD());
                driverSourcePojo.setLinkAttrECopy(driverSourcePojo.getLinkAttrE());
            }
            entity.setDriverSources(JSON.parseObject(JSON.toJSON(driverSourcePojo).toString()));
        }
        if(!slaveSources.isEmpty()){
            List<SlaveSourcePojo> slaveSourceList = slaveSources.toJavaList(SlaveSourcePojo.class);
            for (SlaveSourcePojo slaveSourcePojo : slaveSourceList) {
                //TODO
                if(editAble){
                    if( !Objects.equals("-1",slaveSourcePojo.getLinkAttr())){
                        slaveSourcePojo.setLinkAttrCopy(slaveSourcePojo.getLinkAttr());
                    }
                }else {
                    slaveSourcePojo.setLinkAttrCopy(slaveSourcePojo.getLinkAttr());
                }
            }
            entity.setSlaveSources(JSON.parseArray(JSON.toJSON(slaveSourceList).toString()));
        }
    }

    /**
     * 过滤筛选条件
     * @param entity
     * @param filterList
     * @param jsonArray
     */
    private void setFilter(ChartEntity entity, JSONArray filterList, JSONArray jsonArray) throws XbbException {
        for (int i=0;i<filterList.size();i++){
            JSONObject jsonObject = filterList.getJSONObject(i);
            ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(jsonObject.getString("symbol"));
            //前端筛选条件的值value 有两种可能 String 类型 String[] 数组类型(或空数组)
            if (ConditionEnum.EMPTY.equals(conditionEnum)
                    || ConditionEnum.NOEMPTY.equals(conditionEnum)
                    || ConditionEnum.CUSTOM.equals(conditionEnum)
                    || ConditionEnum.NORMAL.equals(conditionEnum)){
                jsonArray.add(jsonObject);
                continue;
            }
            if (jsonObject.get("value") instanceof String) {
                if (StringUtil.isNotEmpty(jsonObject.getString("value"))) {
                    //将合格的筛选放入jsonArray 最后统一覆盖
                    jsonArray.add(jsonObject);
                }
            } else if (jsonObject.get("value") instanceof List) {
                boolean deleteFlag = false;
                List<Object> valueList = (List<Object>) jsonObject.get("value");
                if (CollectionsUtil.isNotEmpty(valueList)) {
                    // 筛选条件为时间并且是选择范围时，限制不能超过一年
                    if (EsHelper.isDateTimeByFieldType(jsonObject.getInteger(FieldAttrConstant.FIELD_TYPE)) && ConditionEnum.RANGE.equals(conditionEnum) && valueList.size() > 0) {
                        long startTimestamp = valueList.get(0) == null ? 0L : Long.parseLong(valueList.get(0).toString());
                        long endTimestamp = valueList.get(1) == null ? 0L : Long.parseLong(valueList.get(1).toString());
                        if (DateTimeUtil.differenceInDays(startTimestamp, endTimestamp) > TimeConstant.LEAP_YEAR) {
                            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224078, StatisticsServicesErrorCodeEnum.API_ERROR_224078.getMsg(), jsonObject.getString(StringConstant.LABEL_NAME));
                        }
                    }
                    for (Object object : valueList) {
                        if (object instanceof Integer) {
                            if(Integer.valueOf(object.toString())==null){
                                deleteFlag = true;
                            }
                        } else if (object instanceof String) {
                            if(StringUtil.isEmpty(String.valueOf(object))){
                                deleteFlag = true;
                            }
                        }else {
                            if(object == null){
                                deleteFlag = true;
                            }
                        }
                    }
                }else {
                    deleteFlag = true;
                }
                if (!deleteFlag){
                    jsonArray.add(jsonObject);
                }
            }
        }
        //清空之前的筛选条件 进行覆盖
        filterList.clear();
        entity.setFilter(jsonArray);
    }
    /**
     * 处理全局的搜索条件
     * @param chartSavePojo
     * @param insertList
     * @param updateList
     * @param now
     * @param categoryId
     */
    private void globalSearch(ChartSavePojo chartSavePojo, List<ChartEntity> insertList, List<ChartEntity> updateList, long now, Long categoryId) {
        JSONArray linkIds = chartSavePojo.getLinkIds();
        if (linkIds != null && !linkIds.isEmpty()) {
            ChartEntity chartEntity = new ChartEntity();
            BeanUtil.copyProperties(chartSavePojo, chartEntity);
            //全局查询条件的占位名称
            String searchChartName = I18nMessageUtil.getMessage(I18nStringConstant.GLOBAL_QUERY_CONDITION);
            chartEntity.setName(searchChartName);
            chartEntity.setChartType(ChartTypeEnum.MULTIPLE_SEARCH.getCode());
            JSONArray showTypeArray = new JSONArray();
            showTypeArray.add(chartEntity.getChartType());
            chartEntity.setShowTypes(showTypeArray);
            //TODO
            chartEntity.setEnable(1);
            chartEntity.setPublish(0);
            chartEntity.setDel(0);
            chartEntity.setStatisticsType(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode());
            chartEntity.setCategoryId2Category(categoryId);

            JSONObject driverSources = JSONObject.parseObject("{}");
            chartEntity.setDriverSources(driverSources);
            chartEntity.setCreatorId(chartSavePojo.getUserId());
            Long chartId = chartSavePojo.getChartId();
            //编辑
            if (chartId != null && chartId > 0) {
                chartEntity.setId(chartId);
                updateList.add(chartEntity);
            } else {
                //新建(如果原来删除过，也是编辑)
                ChartEntity search = chartModel.getSearch(chartSavePojo.getCorpid(),categoryId);
                if(search !=null){
                    chartEntity.setId(search.getId());
                    updateList.add(chartEntity);
                }else{
                    chartEntity.setAddTime(now);
                    insertList.add(chartEntity);
                }
            }
        }else {
            ChartEntity search = chartModel.getSearch(chartSavePojo.getCorpid(),categoryId);
            if(search != null) {
                search.setDel(1);
                updateList.add(search);
            }
        }
    }

    /**
     * 初始化数据源
     * @param chartSavePojo
     * @param chartEntity
     * @throws XbbException
     */
    private void initData(ChartSavePojo chartSavePojo, ChartEntity chartEntity) throws XbbException {
        if(Objects.equals(ChartSourceEnum.DATESET.getCode(),chartEntity.getSingle())){
           return;
        }
        //关联数据实际是多表，但是没有把single改掉
        if(Objects.equals(0,chartEntity.getMuti())){
            ChartEditDTO chartEditDTO = new ChartEditDTO();
            chartEditDTO.setCorpid(chartSavePojo.getCorpid());
            chartEditDTO.setChartId(chartEntity.getId());
            dataWarehouseService.initData(chartEditDTO);

            String userName = chartSavePojo.getLoginUserName();
            // 记录日志
            String logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_UPDATE_CHART_SOURCES);
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.EDIT;
            String memo = String.format(logMemoUpdateTemplate, userName, chartEntity.getName());
            mongoLogHelp.buildLog(chartSavePojo.getCorpid(), chartSavePojo.getUserId(), userName, OperateModuleTypeEnum.CHART, operateTypeEnum, chartEntity.getId().toString(), chartEntity.getName(), memo, chartSavePojo.getHttpHeader());
        }
    }
    private List<Long> updateInitData(ChartSavePojo chartSavePojo, List<Long> updateIdList, Map<Long, ChartEntity> chartEntityMap,Map<Long, ChartEntity> chartEntityOldMap) throws XbbException {
        List<Long>  initIdList = new ArrayList<>();
        if (!updateIdList.isEmpty()) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            String corpid = chartSavePojo.getCorpid();
            param.put("corpid", corpid);
            param.put("idIn", updateIdList);
            List<ChartEntity> list = chartCustomModel.findEntitys(param);
            if(!list.isEmpty()){
                for (ChartEntity chartEntity : list) {
                    if(Objects.equals(ChartSourceEnum.DATESET.getCode(),chartEntity.getSingle())){
                        continue;
                    }
                    Long chartId = chartEntity.getId();
                    chartEntityOldMap.put(chartId,chartEntity);
                    ChartEntity newChartEntity = chartEntityMap.get(chartId);
                    JSONArray slaveSources = chartEntity.getSlaveSources();
                    JSONArray newSlaveSources = newChartEntity.getSlaveSources();
                    if(!slaveSources.isEmpty()){
                        //如果删除了直接解除关联即可；原来从表不为空，后来从表为空了也要处理解除关联
                        if(Objects.equals(newChartEntity.getDel(),1) || newSlaveSources.isEmpty()){
                            //减少关联
                            decrCorrection(chartEntity);
                        }else {
                            if(chartEqual(chartEntity,newChartEntity)){
                                decrCorrection(chartEntity);
                                initIdList.add(chartEntity.getId());
                            }
                        }
                    }else {
                        //老的没有从表 ，新的有从表
                        if(!newSlaveSources.isEmpty()){
                            initIdList.add(chartEntity.getId());
                        }else {
                            // 单表  有负责人  考虑到单表的表单设计页可能有字段增加
                            if(!EsUtil.getSingle(newChartEntity) && CollectionsUtil.isEmpty(newSlaveSources)){
                                //原来是单表没有负责人
                                if(EsUtil.getSingle(chartEntity)){
                                    initIdList.add(chartEntity.getId());
                                }else{
                                    //判断新加的字段是不是表单模板里新加的
                                    JSONObject formIdAttr = chartEntity.getFormIdAttr();
                                    //防止脏数据
                                    if(formIdAttr == null || formIdAttr.size()==0){
                                        continue;
                                    }
                                    JSONObject formIdAttrJSONObject = formIdAttr.getJSONObject(chartEntity.getDriverSources().get("formId").toString());
                                    //防止特殊情况，如服务器重启，中断，导致formIdAttr中是编辑前的数据， 因此这里加个判空。
                                    if(Objects.isNull(formIdAttrJSONObject)){
                                        continue;
                                    }
                                    Set<String> keySet = formIdAttrJSONObject.keySet();
                                    if (containsNewKey(keySet, newChartEntity.getDisplayAttr()) || containsNewKey(keySet, newChartEntity.getRowGroupAttr()) || containsNewKey(keySet, newChartEntity.getColGroupAttr())
                                            || containsNewKey(keySet, newChartEntity.getSummaryAttr()) || containsNewKey(keySet, newChartEntity.getComputedNumAttr())|| containsNewKey(keySet, newChartEntity.getChartClassify())
                                            || containsNewKey(keySet, newChartEntity.getChartSeries()) || containsNewKey(keySet, newChartEntity.getChartValue())|| containsNewKey(keySet, newChartEntity.getPenetrateAttr())
                                            || containsNewKey(keySet, newChartEntity.getSearch()) || containsNewKey(keySet, newChartEntity.getFilter())
                                    ) {
                                        initIdList.add(chartEntity.getId());
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return initIdList;
    }

    private boolean containsNewKey(Set<String> keySet, JSONArray displayArray) {
        if(CollectionsUtil.isNotEmpty(displayArray)) {
            for (int i = 0; i < displayArray.size(); i++) {
                JSONObject jsonObject = displayArray.getJSONObject(i);
                String originalAttr = jsonObject.getString("originalAttr");
                if(!keySet.contains(originalAttr)){
                    return true;
                }

            }
        }
        return false;
    }

    /**
     * 判断数据源是否需要变动
     * @param chartEntity
     * @param newChartEntity
     * @return  不相等的时候返回true
     */
    private boolean chartEqual(ChartEntity chartEntity,ChartEntity newChartEntity) {
        Set<String> attrSet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        JSONObject olddriverSources = chartEntity.getDriverSources();
        //只有关联字段在最前面加"_"
        attrSet.add(getDriverStr(olddriverSources));
        JSONArray oldslaveSources = chartEntity.getSlaveSources();
        if(CollectionsUtil.isNotEmpty(oldslaveSources)){
            for (int i = 0; i < oldslaveSources.size(); i++) {
                JSONObject sJson = oldslaveSources.getJSONObject(i);
                attrSet.add("_"+sJson.get("formId")+"_"+sJson.get("linkAttr"));
            }
        }
        appendAttr(attrSet, chartEntity.getDisplayAttr());
        //appendAttr(attrSet, chartEntity.getGroupAttr());
        appendAttr(attrSet, chartEntity.getRowGroupAttr());
        if (CollectionsUtil.isNotEmpty(chartEntity.getColGroupAttr())) {
            appendAttr(attrSet, chartEntity.getColGroupAttr());
        }
        appendAttr(attrSet, chartEntity.getSummaryAttr());
        appendAttr(attrSet, chartEntity.getChartClassify());
        appendAttr(attrSet, chartEntity.getChartSeries());
        appendAttr(attrSet, chartEntity.getChartValue());
        appendAttr(attrSet, chartEntity.getPenetrateAttr());
        appendAttr(attrSet, chartEntity.getFilter());
        appendAttr(attrSet,chartEntity.getComputedNumAttr());
        //数据权限字段校验
        JSONObject permissions = chartEntity.getPermissions();
        JSONObject dataPermissionAttr = permissions == null ? null : permissions.getJSONObject("dataPermissionAttr");
        if (dataPermissionAttr != null && !dataPermissionAttr.isEmpty()) {
            JSONArray dataPermissionArray = new JSONArray();
            dataPermissionArray.add(dataPermissionAttr);
            appendAttr(attrSet, dataPermissionArray);
        }
        //判断开始
        if(!attrSet.contains(getDriverStr(newChartEntity.getDriverSources()))){
            return true;
        }
        JSONArray newslaveSources = newChartEntity.getSlaveSources();
        if(CollectionsUtil.isNotEmpty(newslaveSources)){
            for (int i = 0; i < newslaveSources.size(); i++) {
                JSONObject sJson = newslaveSources.getJSONObject(i);
                if(!attrSet.contains("_"+sJson.get("formId")+"_"+sJson.get("linkAttr"))){
                    return true;
                }
            }
        }
        if (judgeContains(attrSet, newChartEntity.getDisplayAttr())) {
            return true;
        }
//        if (judgeContains(attrSet, newChartEntity.getGroupAttr())) {
//            return true;
//        }
        if (judgeContains(attrSet, newChartEntity.getRowGroupAttr())) {
            return true;
        }
        if (judgeContains(attrSet, newChartEntity.getColGroupAttr())) {
            return true;
        }
        if (judgeContains(attrSet, newChartEntity.getSummaryAttr())) {
            return true;
        }
        if (judgeContains(attrSet, newChartEntity.getChartClassify())) {
            return true;
        }
        if (judgeContains(attrSet, newChartEntity.getChartSeries())) {
            return true;
        }
        if (judgeContains(attrSet, newChartEntity.getChartValue())) {
            return true;
        }
        if (judgeContains(attrSet, newChartEntity.getPenetrateAttr())) {
            return true;
        }
        if (judgeContains(attrSet, newChartEntity.getFilter())) {
            return true;
        }
        if (judgeContains(attrSet, newChartEntity.getComputedNumAttr())) {
            return true;
        }
        //数据权限字段校验
        JSONObject newPermissions = newChartEntity.getPermissions();
        JSONObject newDataPermissionAttr = newPermissions == null ? null : newPermissions.getJSONObject("dataPermissionAttr");
        if (newDataPermissionAttr != null) {
            JSONArray dataPermissionArray = new JSONArray();
            dataPermissionArray.add(newDataPermissionAttr);
            if (judgeContains(attrSet, dataPermissionArray)) {
                return true;
            }
        }
        return  false;
    }

    private boolean judgeContains(Set<String> attrSet, JSONArray jsonArray) {
        if(CollectionsUtil.isNotEmpty(jsonArray)) {
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String originalAttr = jsonObject.getString("originalAttr");
                originalAttr = StringUtil.isNotEmpty(originalAttr) ? originalAttr : jsonObject.getString("attr");
                if (!attrSet.contains(jsonObject.getString("formId") + "_" + originalAttr)) {
                    return true;
                }
            }
        }
        return false;
    }

    private String getDriverStr(JSONObject olddriverSources) {
        return "_"+olddriverSources.get("formId")+"_"+olddriverSources.get("linkAttr")+"_"+olddriverSources.get("linkAttrB")+"_"+olddriverSources.get("linkAttrC")+"_"+olddriverSources.get("linkAttrD")+"_"+olddriverSources.get("linkAttrE");
    }

    private void appendAttr(Set<String> set, JSONArray displayAttr) {
        if(CollectionsUtil.isNotEmpty(displayAttr)){
            for (int i = 0; i < displayAttr.size(); i++) {
                JSONObject jsonObject = displayAttr.getJSONObject(i);
                String originalAttr = jsonObject.getString("originalAttr");
                originalAttr = StringUtil.isNotEmpty(originalAttr)?originalAttr: jsonObject.getString("attr");
                set.add(jsonObject.getString("formId")+"_"+originalAttr);
            }
        }
    }

    /**
     * 减少关联
     * @param chartEntity
     * @throws XbbException
     */
    private void decrCorrection(ChartEntity chartEntity) throws XbbException {
        List<BiProWareEntity> list = biProWareService.getBiProWareEntities(chartEntity);
        if (list != null && !list.isEmpty()) {
            //原来是否存在数据源(被删除过的，上面已经判断过没有被删除的)
            BiProWareEntity biProWarehouseEntity = list.get(0);
            biProWarehouseEntity.setIsDone(1);
            long now = DateUtil.getInt();
            biProWarehouseEntity.setUpdateTime(now);
            Integer isCorrelation = biProWarehouseEntity.getIsCorrelation()-1;
            if(isCorrelation < 0){
                isCorrelation = 0;
            }
            biProWarehouseEntity.setIsCorrelation(isCorrelation);
            biProWareModel.update(biProWarehouseEntity);
        }

    }

    /**
     * 获取指标的分类id
     * @param corpid
     * @param alias
     * @return
     * @throws XbbException
     */
    private Long getCateoryId4Alias(String corpid, String alias, int type) throws XbbException {
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid",corpid);
        param.put("type", type);
        param.put("alias", alias);
        param.put("del",0);
        List<ChartCategoryEntity> categoryList = chartCategoryModel.findEntitys(param);
        Long categoryId ;
        if(CollectionsUtil.isNotEmpty(categoryList)){
            categoryId = categoryList.get(0).getId();
        } else {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224018);
        }
        return categoryId;
    }


    /*------------------------------------privet方法-----------------------------------------*/
    /**
     * 过滤条件处理
     *
     * @param entity 图表实体
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/4/27 9:35
     * @version 1.0
     */
    private void handleFilter(ChartEntity entity) {
        JSONArray filter = entity.getFilter();
        JSONArray temporFilter = new JSONArray();
        if(CollectionUtils.isNotEmpty(filter)){
            JSONObject driverSources = entity.getDriverSources();
            for(int i=0;i<filter.size();i++){
                JSONObject filterJson = filter.getJSONObject(i);
                JSONArray jsonArray= filterJson.getJSONArray("value");
                List<Object> valueList = null;
                if(CollectionsUtil.isNotEmpty(jsonArray)){
                    valueList = JSONArray.parseArray(jsonArray.toJSONString(),Object.class);
                }
                if(filterJson.containsKey(StringConstant.SYMBOL)){
                    if(Objects.equals(filterJson.getString(StringConstant.SYMBOL), ConditionEnum.NOEMPTY.getSymbol())
                            || Objects.equals(filterJson.getString(StringConstant.SYMBOL), ConditionEnum.EMPTY.getSymbol())
                            || Objects.equals(filterJson.getString(StringConstant.SYMBOL), ConditionEnum.NORMAL.getSymbol())
                            || Objects.equals(filterJson.getString(StringConstant.SYMBOL), ConditionEnum.CUSTOM.getSymbol())){
                        filterJson.put("formId", driverSources.getLong("formId"));
                        temporFilter.add(filterJson);
                    }
                }
                if(CollectionsUtil.isNotEmpty(valueList)){
                    filterJson.put("formId", driverSources.getLong("formId"));
                    temporFilter.add(filterJson);
                }
            }
            entity.setFilter(temporFilter);
        }
    }

    /**
     * 首页看板自定义指标保存
     * @param chartCustomSaveDTO
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartCustomSaveVO
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/4/27 10:15
     * @version 1.0
     */
    private ChartCustomSaveVO customSave4board(ChartCustomSaveDTO chartCustomSaveDTO) throws XbbException {
        ChartCustomSaveVO chartCustomSaveVO = new ChartCustomSaveVO();
        ChartEntity chartEntity = chartCustomSaveDTO.getChartEntity();
        Long id = chartEntity.getId();
        if (id != null && id > 0) {
            // 编辑
            chartEntity.setCategory(null);
            id = Long.valueOf(chartCustomModel.update(chartEntity));
            String logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_UPDATE_CHART_VALUE);
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.EDIT;
            chartCustomSaveVO.setId(id);
            chartCustomSaveVO.setLogMemoUpdateTemplate(logMemoUpdateTemplate);
            chartCustomSaveVO.setOperateTypeEnum(operateTypeEnum);
        } else {
            // 新建
            Long categoryId = getCateoryId4Alias(chartEntity.getCorpid(), ChartCategoryAliasEnum.REPORT_BOARD.getAlias(), ChartCategoryTypeEnum.WEB_INDEX_LEFT.getCode());
            chartEntity.setCategoryId2Category(categoryId);
            id = Long.valueOf(chartCustomModel.insert(chartEntity));
            String logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_ADD_CHART_VALUE);
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.NEW;
            chartCustomSaveVO.setId(id);
            chartCustomSaveVO.setLogMemoUpdateTemplate(logMemoUpdateTemplate);
            chartCustomSaveVO.setOperateTypeEnum(operateTypeEnum);
        }
        return chartCustomSaveVO;
    }

    /**
     * pk自定义指标保存
     * @param chartCustomSaveDTO
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartCustomSaveVO
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/4/27 10:15
     * @version 1.0
     */
    private ChartCustomSaveVO customSave4Pk(ChartCustomSaveDTO chartCustomSaveDTO) throws XbbException {
        ChartCustomSaveVO chartCustomSaveVO = new ChartCustomSaveVO();
        ChartEntity chartEntity = chartCustomSaveDTO.getChartEntity();
        Long id = chartEntity.getId();
        String name = chartEntity.getName();
        String corpid = chartEntity.getCorpid();
        if (id != null && id > 0) {
            /* 编辑 */
            // 自定义pk需要更新图表名称
            ChartDTO chartDTO = new ChartDTO();
            BeanUtil.copyProperties(chartCustomSaveDTO, chartDTO);
            // 前端传回来的Category可能会有问题，还是查一下吧
            ChartEntity chartEntityByKey = chartCustomModel.getByKey(id, corpid);
            chartDTO.getChartEntity().setCategory(chartEntityByKey.getCategory());
            // 查分类
            List<ChartCategoryEntity> categoryEntityList = getCategoryList4Pk(chartDTO);
            if (CollectionUtils.isNotEmpty(categoryEntityList)) {
                // 把分类名的开启状态同步一下，编辑后默认开启
                categoryEntityList.forEach(i -> {
                    i.setName(name);
                    i.setNameEn(name);
                    i.setEnable(BasicConstant.IS_USE);
                });
                chartCategoryModel.updateBatch(categoryEntityList, chartCustomSaveDTO.getCorpid());
            }
            // 解释里的position参数不能丢，不然选择已有图表那会有问题
            JSONObject explains = chartEntity.getExplains();
            explains.put(StringConstant.Position, chartEntityByKey.getExplains().get(StringConstant.Position));
            // 更新图表
            id = Long.valueOf(chartCustomModel.update(chartEntity));
            // 格式化日志参数
            String logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_UPDATE_CHART_PK_VALUE);
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.EDIT;
            chartCustomSaveVO.setId(id);
            chartCustomSaveVO.setLogMemoUpdateTemplate(logMemoUpdateTemplate);
            chartCustomSaveVO.setOperateTypeEnum(operateTypeEnum);
        } else {
            /* 新建 */
            // 判断是否超过套餐数量
            Integer status = packageStatusHelp.getPackageStatus(corpid, ValueAddedTypeEnum.CUSTOM_CHART_NUM, BasicConstant.ONE);
            if(!Objects.equals(status, PackageStatusEnum.NORMAL.getCode()) && !Objects.equals(status, PackageStatusEnum.WARNING.getCode())){
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224031);
            }
            // 保存图表分类
            ChartCategorySaveDTO chartCategorySaveDTO = new ChartCategorySaveDTO();
            BeanUtil.copyProperties(chartCustomSaveDTO, chartCategorySaveDTO);
            Long categoryId4PkUser = getCateoryId4Alias(corpid, ChartCategoryEnum.PK_USER.getAlias(), ChartCategoryTypeEnum.PK_USER.getCode());
            chartCategorySaveDTO.setParentId(categoryId4PkUser);
            chartCategorySaveDTO.setName(name);
            chartCategorySaveDTO.setNameEn(name);
            ChartCategorySaveVO chartCategorySaveVO = chartCategoryService.chartCategorySave(chartCategorySaveDTO);
            // 获取分类id
            Long categoryId = getCateoryId4Alias(corpid, ChartCategoryAliasEnum.PK.getAlias(), ChartCategoryTypeEnum.WEB_INDEX_LEFT.getCode());
            chartEntity.setCategoryId2Category(categoryId);
            // 图表分类的id也保存，回显用
            chartEntity.setCategory(chartEntity.getCategory().fluentAdd(chartCategorySaveVO.getId()));
            // 保存指标、图表
            id = Long.valueOf(chartCustomModel.insert(chartEntity));
            // 格式化日志参数
            String logMemoUpdateTemplate = I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_USER_ADD_CHART_PK_VALUE);
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.NEW;
            chartCustomSaveVO.setId(id);
            chartCustomSaveVO.setLogMemoUpdateTemplate(logMemoUpdateTemplate);
            chartCustomSaveVO.setOperateTypeEnum(operateTypeEnum);
        }
        return chartCustomSaveVO;
    }

    /**
     * 获取所有分类,pk榜用
     * @param chartDTO
     * @return java.util.List<com.xbongbong.pro.domain.entity.ChartCategoryEntity>
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/5/14 10:38
     * @version 1.0
     */
    private List<ChartCategoryEntity> getCategoryList4Pk(ChartDTO chartDTO) {
        // feign调用获取所有分类
        String result = paasFormFeignClient.getCategoryList4Pk(chartDTO, LocaleContextHolder.getLocale().toString());
        // 反序列化
        XbbResponse<List<ChartCategoryEntity>> xbbResponse = JSON.parseObject(result, new TypeReference <XbbResponse<List<ChartCategoryEntity>>>() {
        }, Feature.OrderedField);
        List<ChartCategoryEntity> categoryEntityList = xbbResponse.getResult();
        return categoryEntityList;
    }

    /**
     * 更新自定义pk操作权限
     * @param chartSystemSavePojo
     * @param chartEntityEtx
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/5/26 10:10
     * @version 1.0
     */
    private ChartBatchSaveVo pkCustomPermissionsUpdate(ChartSystemSavePojo chartSystemSavePojo, ChartEntityEtx chartEntityEtx, ChartBatchSaveVo chartBatchSaveVo) throws XbbException {
        CategoryPermissionSaveDTO categoryPermissionSaveDTO = new CategoryPermissionSaveDTO();
        BeanUtil.copyProperties(chartSystemSavePojo, categoryPermissionSaveDTO);
        // 获取权限
        categoryPermissionSaveDTO.setPermissions(chartEntityEtx.getPermissions());
        // 获取分类id,前端传过来是空的
        ChartDTO chartDTO = new ChartDTO();
        BeanUtil.copyProperties(chartSystemSavePojo, chartDTO);
        ChartEntity chartEntity = chartCustomModel.getByKey(chartEntityEtx.getId(), chartEntityEtx.getCorpid());
        chartDTO.setChartEntity(chartEntity);
        List<ChartCategoryEntity> categoryList4Pk = getCategoryList4Pk(chartDTO);
        if (CollectionsUtil.isEmpty(categoryList4Pk)) {
            LOG.error("自定义pk，操作权限跟新时分类id查询有误！");
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
        }
        categoryPermissionSaveDTO.setCategoryId(categoryList4Pk.get(0).getId());
        chartCategoryService.categoryPermissionUpdate(categoryPermissionSaveDTO);

        List <ChartSaveUuidVO> chartSaveUuidList = new ArrayList<>();
        ChartSaveUuidVO chartSaveUuidVO = new ChartSaveUuidVO();
        chartSaveUuidVO.setId(chartEntityEtx.getId());
        chartSaveUuidList.add(chartSaveUuidVO);
        chartBatchSaveVo.setChartList(chartSaveUuidList);
        return chartBatchSaveVo;
    }

    /**
     * 获取分类的权限
     * @param chartDTO
     * @return com.alibaba.fastjson.JSONObject
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/5/26 14:11
     * @version 1.0
     */
    private JSONObject getChartCategoryPermissions(ChartDTO chartDTO) throws XbbException {
        List<ChartCategoryEntity> categoryList4Pk = getCategoryList4Pk(chartDTO);
        if (CollectionsUtil.isEmpty(categoryList4Pk)) {
            LOG.error("自定义pk，操作权限获取时分类id查询有误！");
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
        }
        return categoryList4Pk.get(0).getPermissions();
    }
    @Override
    public SummaryAttrVO searchSummaryAttr(SummaryAttrGetDTO summaryAttrGetDTO) throws XbbException {
        Long chartId = summaryAttrGetDTO.getChartId();
        String corpid = summaryAttrGetDTO.getCorpid();
        JSONObject formIdBusinessTypeList = summaryAttrGetDTO.getFormIdBusinessTypeList();

        // 1.如果chartId不为空查询出图表关联的数据源
        ChartEntity chartEntity ;
        JSONObject driverSourcesObject;
        JSONArray slaveSources;
        List<DataWarningFieldAttrPojo> fieldCountConditionList = new ArrayList<>();
        List<DataWarningFieldAttrPojo> fieldConditionList = new ArrayList<>();

        if (Objects.nonNull(chartId)){
            chartEntity = chartCustomModel.getByKey(chartId,corpid);
            JSONArray chartValue = chartEntity.getChartValue();
            JSONArray chartSecondValue = chartEntity.getChartValueSecond();
            List<FieldAttrPojo> fieldAttrPojoList = new ArrayList<>();
            List<FieldAttrPojo> fieldAttrPojoSecondList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(chartValue)){
                fieldAttrPojoList = JSON.parseArray(chartEntity.getChartValue().toJSONString(), FieldAttrPojo.class);
            }
            if (CollectionUtils.isNotEmpty(chartSecondValue)){
                fieldAttrPojoSecondList = JSON.parseArray(chartEntity.getChartValueSecond().toJSONString(), FieldAttrPojo.class);
                fieldAttrPojoList.addAll(fieldAttrPojoSecondList);
            }
            if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.TARGET_CHART.getCode()) || Objects.equals(chartEntity.getChartType(),ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())){
                fieldAttrPojoList = JSON.parseArray(chartEntity.getSummaryAttr().toJSONString(), FieldAttrPojo.class);
            }
            // 去重 防止重复
            List<String> idList = new ArrayList<>();
            fieldAttrPojoList.forEach(fieldAttrPojo ->{
                fieldConditionList.add(new DataWarningFieldAttrPojo(){{
                    String id = fieldAttrPojo.getAttr() + "&" +fieldAttrPojo.getFormId();
                    if (!idList.contains(id)){
                        idList.add(id);
                        setId(id);
                        if (Objects.isNull(fieldAttrPojo.getOriginalAttr())){
                            setAttr(fieldAttrPojo.getAttr());
                        }else {
                            setAttr(fieldAttrPojo.getOriginalAttr());
                        }
                        setAttrName(fieldAttrPojo.getAttrName());
                        setFormId(fieldAttrPojo.getFormId());
                        setFieldType(fieldAttrPojo.getFieldType());
                        setBusinessType(fieldAttrPojo.getBusinessType());
                        setLabelName(fieldAttrPojo.getLabelName());
                        setAdvancedComputing(fieldAttrPojo.getAdvancedComputing());
                        setAggType(fieldAttrPojo.getAggType());
                    }
                }});
            });
//            if (Objects.isNull(chartEntity)){
//                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
//            }
//            driverSourcesObject = chartEntity.getDriverSources();
//            slaveSources=chartEntity.getSlaveSources();
//
//            // 2.将结果拼成formIdBusinessTypeList (formId:businessType)
//            formIdBusinessTypeList = new JSONObject();
//            if (Objects.nonNull(driverSourcesObject)){
//                formIdBusinessTypeList.put(String.valueOf(driverSourcesObject.getLong("formId")),driverSourcesObject.getInteger("businessType"));
//                fieldCountConditionList.add(new DataWarningFieldAttrPojo(){{
//                    setId("count&" + driverSourcesObject.getLong("formId"));
//                    setAttr("count");
//                    setAttrName(driverSourcesObject.getString("name") + "-计数");
//                    setFormId(driverSourcesObject.getLong("formId"));
//                    setFieldType(FieldTypeEnum.NUM.getType());
//                    setBusinessType(driverSourcesObject.getInteger("businessType"));
//                }});
//            }
//
//            JSONObject finalFormIdBusinessTypeList = formIdBusinessTypeList;
//            slaveSources.forEach(item->{
//                JSONObject slaveSourcesObj = (JSONObject) item;
//                finalFormIdBusinessTypeList.put(String.valueOf(slaveSourcesObj.getLong("formId")),slaveSourcesObj.getInteger("businessType"));
//                fieldCountConditionList.add(new DataWarningFieldAttrPojo(){{
//                    setId("count&" + slaveSourcesObj.getLong("formId"));
//                    setAttr("count");
//                    setAttrName(slaveSourcesObj.getString("name") + "-计数");
//                    setFormId(slaveSourcesObj.getLong("formId"));
//                    setFieldType(FieldTypeEnum.NUM.getType());
//                    setBusinessType(slaveSourcesObj.getInteger("businessType"));
//                }});
//            });
//            formIdBusinessTypeList = finalFormIdBusinessTypeList;

        }else if (!ObjectUtils.isEmpty(formIdBusinessTypeList)){
            // formId和businessType不为空
//            formIdBusinessTypeList = summaryAttrGetDTO.getFormIdBusinessTypeList();
//            Map<String, Integer> formIdBusinessTypeMap = JSONObject.toJavaObject(formIdBusinessTypeList, Map.class);
//            formIdBusinessTypeMap.forEach((k,v)->{
//                PaasFormEntity paasFormEntity = paasFormModel.getByFormId(Long.parseLong(k), corpid);
//                if (null != paasFormEntity){
//                    fieldCountConditionList.add(new DataWarningFieldAttrPojo(){{
//                        setId("count&"+Long.parseLong(k));
//                        setAttr("count");
//                        setAttrName(paasFormEntity.getName() + "-计数");
//                        setFormId(Long.parseLong(k));
//                        setFieldType(FieldTypeEnum.NUM.getType());
//                        setBusinessType(paasFormEntity.getBusinessType());
//                    }});
//                }
//            });
        }

        // 3.传入searchNumberAttr方法查出数字字段
//        JSONObject finalFormIdBusinessTypeList = formIdBusinessTypeList;
//        FormIdBusinessTypeAttrDTO formIdBusinessTypeAttrDTO = new FormIdBusinessTypeAttrDTO(){{
//            setCorpid(summaryAttrGetDTO.getCorpid());
//            setUserId(summaryAttrGetDTO.getUserId());
//            setPlatform(summaryAttrGetDTO.getPlatform());
//            setHttpHeader(summaryAttrGetDTO.getHttpHeader());
//            setLoginUser(summaryAttrGetDTO.getLoginUser());
//            setLoginUserName(summaryAttrGetDTO.getLoginUserName());
//            setFormIdBusinessTypeList(finalFormIdBusinessTypeList);
//        }};
        SummaryAttrVO summaryAttrVO = new SummaryAttrVO(){{
//            NumberAttrVO numberAttrVO = searchNumberAttr(formIdBusinessTypeAttrDTO);
//            setSummaryAble(numberAttrVO.getNumberAble());
//            List<DataWarningFieldAttrPojo> fieldConditionList = new ArrayList<>();
//            numberAttrVO.getNumberAble().forEach(item ->{
//                List<DataWarningFieldAttrPojo> warningFieldAttrPojoList = ((List<FieldAttrEntity>) item.getFieldList()).stream().map(e -> new DataWarningFieldAttrPojo((e.getAttr() +"&"+item.getFormId()), e.getAttr(),e.getAttrName(),e.getFieldType(),e.getVisible(),item.getFormId(),e.getBusinessType())).collect(Collectors.toList());
//                if (Objects.nonNull(warningFieldAttrPojoList)){
//                    fieldConditionList.addAll(warningFieldAttrPojoList);
//                }
//            });
            setFieldAttrArray(fieldConditionList);
        }};

        return summaryAttrVO;
    }

    @Override
    public ChartInfoDwVO chartList4Dw(ChartListDwDTO chartList4DwDTO) throws XbbException {
        ChartInfoDwVO chartInfoDwVO = new ChartInfoDwVO();
        // 获取套餐内数量的chartId
        String corpid = chartList4DwDTO.getCorpid();
        List<Long> chartIdList = updatePackageRedisService.getPackageTotalChartId(corpid);
        Integer num = updatePackageRedisService.getUnusedNumPackageLimit(corpid, ValueAddedTypeEnum.CUSTOM_CHART_NUM);
        // 获取套餐下的功能
        List<String> featureList = packageHelp.getFeatureList(corpid);

        if (Objects.nonNull(chartList4DwDTO.getIds())){
            chartIdList.stream().filter(item -> chartList4DwDTO.getIds().contains(item)).collect(Collectors.toList());
        }
        Map<String, Object> map = BeanUtil.convertBean2Map(chartList4DwDTO, true);
//        map.put("idIn",chartIdList);

        List<ChartEntity> chartList = (List<ChartEntity>) BasicHelper.findEntitysByImitatePage(map, chartCustomModel, BasicConstant.THREE_HUNDRED);
        // 套餐限制
        chartList.stream().filter(item ->  !packageHelp.packageLimitFlag(chartIdList, item.getId(), item.getStatisticsType(), num, featureList)).collect(Collectors.toList());
        List<ChartInfoDwPojo> infoDwList = new ArrayList<>();
        try {
            BeanUtil.copyPropertiesList(chartList,infoDwList,ChartInfoDwPojo.class);
        } catch (Exception e) {
            LOG.error("copy数组失败");
        }

        // 图表中心全局权限控制 (新建，编辑，删除)
        JSONObject overAllPermissions = customHelp.chartOverallPermissions(chartList4DwDTO);
        Map<Long, List<Long>> subDepIdMap = departmentModel.getSubDepIdMap(chartList4DwDTO.getCorpid(), false);
        // 图表中心编辑权限
        boolean viewPermissions = ProPermissionHelp.hasThisPermission(chartList4DwDTO.getLoginUser(), ChartProPermissionAliasEnum.CHART_VIEW.getAlias());
        boolean newPermissions = ProPermissionHelp.hasThisPermission(chartList4DwDTO.getLoginUser(), ChartProPermissionAliasEnum.CHART_ADD.getAlias());
        boolean editPermissions = ProPermissionHelp.hasThisPermission(chartList4DwDTO.getLoginUser(), ChartProPermissionAliasEnum.CHART_UPDATE.getAlias());
        // 仪表盘过滤可见权限后的categoryIds(二级分类权限过滤)
        Set<Long> categoryIds = chartList.stream().map(ChartEntity::getCategoryId).collect(Collectors.toSet());
        map.clear();
        map.put("del",0);
        map.put("corpid",chartList4DwDTO.getCorpid());
        map.put("idIn",categoryIds);
        map.put("enable",1);
        List<ChartCategoryEntity> chartCategoryEntityList = chartCategoryModel.findEntitys(map);
        Iterator<ChartCategoryEntity> categoryIterator = chartCategoryEntityList.iterator();
        while (categoryIterator.hasNext()){
            if (!customHelp.judgeCategoryPermissions(categoryIterator.next().getPermissions(), chartList4DwDTO, subDepIdMap)){
                categoryIterator.remove();
            }
        }
        categoryIds = chartCategoryEntityList.stream().map(ChartCategoryEntity::getId).collect(Collectors.toSet());
        Set<Long> finalCategoryIds = categoryIds;
        chartList.removeIf(item ->!finalCategoryIds.contains(item.getCategoryId()));
        // 图表过滤可见权限后的chartIds(图表可见权限过滤)
        Iterator<ChartEntity> iter = chartList.iterator();
        while(iter.hasNext()){
            //可见权限控制
            Map<String, Boolean> permissions = customHelp.isChartPermissions(iter.next().getPermissions(),chartList4DwDTO,overAllPermissions, subDepIdMap);
            if(!permissions.get(ChartProPermissionAliasEnum.CHART_VIEW.getAlias())){
                iter.remove();
            }
        }
        Set<Long> chartIds = chartList.stream().map(ChartEntity::getId).collect(Collectors.toSet());
        // 是否要求权限过滤
        if (Objects.equals(chartList4DwDTO.getFilterPermission(),true)){
            // 图表中心编辑权限没有直接返回
            if (!editPermissions){
                return chartInfoDwVO;
            }
            try {
                infoDwList = new ArrayList<>();
                BeanUtil.copyPropertiesList(chartList,infoDwList,ChartInfoDwPojo.class);
            } catch (Exception e) {
                LOG.error("copy数组失败");
            }
            // 设置权限
            infoDwList.forEach(item ->{
                item.setChartCenterPermission(true);
                item.setCategoryVisiblePermission(true);
                item.setChartVisiblePermission(true);
            });
            chartInfoDwVO.setChartInfoDwPojoList(infoDwList);
        }else {
            for (ChartInfoDwPojo chartInfoDwPojo : infoDwList) {
                if (viewPermissions || newPermissions || editPermissions) {
                    // 图表中心的编辑权限，图表中心没有编辑权限的话不需要判断仪表盘
                    chartInfoDwPojo.setChartCenterPermission(true);
                    if (editPermissions){
                        chartInfoDwPojo.setChartCenterPermission(true);
                    }
                    // 仪表盘的可见权限,仪表盘不可见的话，不需要判断图表
                    if (categoryIds.contains(chartInfoDwPojo.getCategoryId())){
                        chartInfoDwPojo.setCategoryVisiblePermission(true);
                        // 图表可见权限的判断
                        chartInfoDwPojo.setChartVisiblePermission(chartIds.contains(chartInfoDwPojo.getId()));
                    }
                }else {
                    chartInfoDwVO.setChartInfoDwPojoList(infoDwList);
                    return chartInfoDwVO;
                }
            }
            chartInfoDwVO.setChartInfoDwPojoList(infoDwList);
        }

        return chartInfoDwVO;
    }

    @Override
    public ChartThroughVO checkThrough(ChartThroughDTO throughDTO) throws XbbException {
        ChartThroughVO chartMessageThroughVO = new ChartThroughVO();
        // 获取套餐内数量的chartId
//        List<Long> chartIdList = packageHelp.getPackageTotalChartId(throughDTO.getCorpid());
//        if (!chartIdList.contains(throughDTO.getChartId())){
//            chartMessageThroughVO.setHasPermission(false);
//            return chartMessageThroughVO;
//        }

        // 预警是否被删除
        DataWarningEntity dataWarningEntity = dataWarningModel.getByKey(throughDTO.getDataWarningId(),throughDTO.getCorpid());
        if (null == dataWarningEntity ){
            chartMessageThroughVO.setDelFlag(true);
        }else {
            if (Objects.equals(dataWarningEntity.getEnable(),0)){
                chartMessageThroughVO.setEnableFlag(true);
            }
        }
        // 查找到最新创建的仪表盘
        ChartEntity chartEntity = chartCustomModel.getByKey(throughDTO.getChartId(),throughDTO.getCorpid());
        if (null == chartEntity || Objects.equals(chartEntity.getDel(),1)){
            chartMessageThroughVO.setDelFlag(true);
        }
        JSONArray jsonArray ;
        if (null != chartEntity && null != (jsonArray = chartEntity.getCategory()) ){
            Long categoryId = throughDTO.getCategoryId();
            ChartCategoryEntity categoryEntity = chartCategoryModel.getByKey(categoryId,throughDTO.getCorpid());
            if (Objects.isNull(categoryEntity) || ( Objects.nonNull(categoryEntity) && Objects.equals(categoryEntity.getEnable(),0))){
                categoryId = null;
            }
            for (Object item : jsonArray) {
                if ((Objects.isNull(categoryId) && !Objects.equals(throughDTO.getCategoryId(),Long.parseLong(item.toString()))) || (Objects.nonNull(categoryId) && Long.parseLong(item.toString()) > categoryId)) {
                    ChartCategoryEntity categoryEntityTemp = chartCategoryModel.getByKey(Long.parseLong(item.toString()),throughDTO.getCorpid());
                    if (Objects.nonNull(categoryEntityTemp) && Objects.equals(categoryEntityTemp.getEnable(),1)){
                        categoryId = categoryEntityTemp.getId();
                    }
                }
            }
            if (Objects.isNull(categoryId)){
                chartMessageThroughVO.setHasPermission(false);
                return chartMessageThroughVO;
            }
            throughDTO.setCategoryId(categoryId);
            chartMessageThroughVO.setCategoryId(categoryId);
        }

        // 不是从消息那边穿透过来的
        if (Objects.isNull(throughDTO.getCategoryId()) || Objects.isNull(throughDTO.getChartId())){
            return chartMessageThroughVO;
        }
        // 是否是超管
        if (null !=throughDTO.getLoginUser() && throughDTO.getLoginUser().isAdminOrBoss()){
            return chartMessageThroughVO;
        }

        // 图表中心权限
        JSONObject overAllPermissions = customHelp.chartOverallPermissions(throughDTO);
        boolean viewPermissions = ProPermissionHelp.hasThisPermission(throughDTO.getLoginUser(), ChartProPermissionAliasEnum.CHART_VIEW.getAlias());
        boolean newPermissions = ProPermissionHelp.hasThisPermission(throughDTO.getLoginUser(), ChartProPermissionAliasEnum.CHART_ADD.getAlias());
        boolean editPermissions = ProPermissionHelp.hasThisPermission(throughDTO.getLoginUser(), ChartProPermissionAliasEnum.CHART_UPDATE.getAlias());

        if (!(viewPermissions || newPermissions || editPermissions)){
            chartMessageThroughVO.setHasPermission(false);
            return chartMessageThroughVO;
        }

        // 仪表盘可见权限
        ChartCategoryEntity categoryEntity = chartCategoryModel.getByKey(throughDTO.getCategoryId(),throughDTO.getCorpid());
        Map<Long, List<Long>> subDepIdMap = departmentModel.getSubDepIdMap(throughDTO.getCorpid(), false);
        if (Objects.isNull(categoryEntity) || !customHelp.judgeCategoryPermissions(categoryEntity.getPermissions(), throughDTO, subDepIdMap)){
            chartMessageThroughVO.setHasPermission(false);
            return chartMessageThroughVO;
        }

        // 图表可见权限(只有图表中心是查看权限的，才区分图表的可见不可见)
        if (Objects.isNull(chartEntity) || (!(newPermissions || editPermissions) && !customHelp.isChartPermissions(categoryEntity.getPermissions(),throughDTO,overAllPermissions, subDepIdMap).get((ChartProPermissionAliasEnum.CHART_VIEW.getAlias())))){
            chartMessageThroughVO.setHasPermission(false);
            return chartMessageThroughVO;
        }

        return chartMessageThroughVO;
    }

    @Override
    public ChartTypeListVO chartTypeList(BaseDTO baseDTO) throws XbbException {
        ChartTypeListVO chartTypeListVO = new ChartTypeListVO();
        List<ChartTypeEnum> ordinaryChartList = ChartTypeEnum.getOrdinaryChartList();
        List<ChartTypeEnum> seniorChartList = Collections.emptyList();
        //旗舰版、开启CK
        if(packageHelp.checkSeniorChartPower(baseDTO.getCorpid())){
            seniorChartList = ChartTypeEnum.getSeniorChartList();
            if(!chartLimitService.getCkFlag()){
                seniorChartList.removeAll(ChartTypeEnum.getSpecialType4CK());
            }
        }
        chartTypeListVO.setOrdinaryChartTypeList(customHelp.getChartMemo(ordinaryChartList));
        chartTypeListVO.setSeniorChartTypeList(customHelp.getChartMemo(seniorChartList));
        chartTypeListVO.setSelectExiChartPermission(true);
        return chartTypeListVO;
    }

    @Override
    public BaseVO chartUpdate4Ave(ChartUpdateAveDTO chartUpdateAveDTO) throws XbbException {
        Integer pageSize = 200;
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("del", DelEnum.NORMAL.getDel());
//        param.put("orderByStr", "add_time asc");
        param.put("columns", "corpid");
        // 过滤无效公司（解绑，套餐过期）,套餐时间,过滤标准版
        param.put("status",BasicConstant.ONE);
        Integer companyCount = companyModel.getEntitysCount(param);
        // 遍历公司
        Integer threadNum = companyCount / pageSize + 1;
        LOG.info("********************自定义图表批量更新start********************");
        // 测试用
        if (null != chartUpdateAveDTO.getCorpidList()){
            chartCustomModel.updateBatchAve(chartUpdateAveDTO.getCorpidList());
            return new BaseVO();
        }
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                try {
                    for (int i = 1; i < threadNum + 1; i++) {
                        Integer start = (i - 1) * pageSize;
                        Integer pageNum = i * pageSize;
                        param.put("start", start);
                        param.put("pageNum", pageNum);
                        // 分页循环
                        List<CompanyEntity> companyList = companyModel.findEntitys(param);
                        List<String> corpidIn;
                        if (companyList.size()>0){
                            corpidIn = companyList.stream().map(CompanyEntity::getCorpid).collect(Collectors.toList());
                            LOG.info("********************corpidIn :" + corpidIn + "；开始执行批量更新平均线start********************");
                            chartCustomModel.updateBatchAve(corpidIn);
                            LOG.info("********************" + "成功更新end********************");
                        }
                    }
                    LOG.info("********************自定义图表批量更新end********************");
                } catch (Exception e) {
                    LOG.error(BiErrorCodeEnum.API_ERROR_241006.getMsg());
                }
            }
        };
        threadPoolExecutor.execute(runnable);
        return new BaseVO();
    }

    @Override
    public NumFormatSaveVO saveNumFormat(NumFormatSaveDTO numFormatSaveDTO) throws XbbException {
        NumFormatSaveVO numFormatSaveVO = new NumFormatSaveVO();
        Integer statisticsType = numFormatSaveDTO.getStatisticsType() == null ? StatisticsTypeEnum.ALL.getCode() : numFormatSaveDTO.getStatisticsType();
        ChartResultDTO chartResultDTO = new ChartResultDTO();
        BeanUtil.copyProperties(numFormatSaveDTO, chartResultDTO);
        ChartAnalysisFactory.getChartStrategyService(statisticsType).batchUpdateNumFormat(chartResultDTO);
        return numFormatSaveVO;
    }

    @Override
    public NumFormatGetVO getNumFormat(NumFormatGetDTO numFormatGetDTO) throws XbbException {
        NumFormatGetVO numFormatGetVO = new NumFormatGetVO();
        Integer statisticsType = numFormatGetDTO.getStatisticsType() == null ? StatisticsTypeEnum.ALL.getCode() : numFormatGetDTO.getStatisticsType();
        Integer origin = numFormatGetDTO.getOrigin();
        ChartEntity chartEntity = new ChartEntity();
        ChartResultDTO chartResultDTO = new ChartResultDTO();
        BeanUtil.copyProperties(numFormatGetDTO, chartResultDTO);
        if (Objects.equals(origin, 0)) {
            // 首页数值格式设置是卡片全局设置，对整个卡片内的图表生效，所以这里只取第一个就行
            chartResultDTO.setChartIdIn(Stream.of(chartResultDTO.getChartIdIn().get(0)).collect(Collectors.toList()));
            List<ChartEntity> chartList = ChartAnalysisFactory.getChartStrategyService(statisticsType).getChartList(chartResultDTO);
            if (CollectionsUtil.isNotEmpty(chartList)) {
                chartEntity = chartList.get(0);
            }
        }
        int numFormat = chartEntity.getNumFormat() == null ? NumFormatEnum.DEFAULT.getCode() : chartEntity.getNumFormat();
        numFormatGetVO.setNumFormat(numFormat);
        return numFormatGetVO;
    }

    @Override
    public ChartDrillListVO drillList(ChartDrillListDTO chartDrillListDTO) throws XbbException {
        ChartDrillEntity chartDrillEntity = null;
        Long chartId = chartDrillListDTO.getId();
        if (Objects.nonNull(chartId)) {
            chartDrillEntity = chartDrillModel.getByChartId(chartDrillListDTO.getCorpid(), chartDrillListDTO.getStatisticsType(), chartId);
        }
        List<ChartDrillItemPojo> list;
        Long id = null;
        if (Objects.nonNull(chartDrillEntity)) {
            list = JsonHelperUtil.parseArray(JSONArray.toJSONString(chartDrillEntity.getDrill()), ChartDrillItemPojo.class);
            id = chartDrillEntity.getId();
        } else {
            list = new ArrayList<>();
        }
        ChartDrillListPojo drill = new ChartDrillListPojo(list);
        drill.setId(id);
        return new ChartDrillListVO(drill);
    }

    @Override
    public BaseVO operateEnable(ChartOperateEnableDTO chartOperateEnableDTO) throws XbbException {
        String operate = chartOperateEnableDTO.getOp();
        ChartOperateEnum operateEnum = ChartOperateEnum.getByAlias(operate);
        if (Objects.isNull(operateEnum)) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224011, StatisticsServicesErrorCodeEnum.API_ERROR_224011.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.CHART_OPERATE_ENABLE));
        }

        Integer statisticsType = chartOperateEnableDTO.getStatisticsType();
        Long chartId = chartOperateEnableDTO.getId();
        String corpid = chartOperateEnableDTO.getCorpid();
        ChartEntity entity = ChartAnalysisFactory.getChartStrategyService(statisticsType).getByKey(chartId, corpid);
        if(Objects.isNull(entity)){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012);
        }
        JSONObject explains = entity.getExplains();
        if(Objects.isNull(explains)){
            //没有则初始化
            explains = new JSONObject();

        }
        ExplainsPojo explainsPojo = explains.toJavaObject(ExplainsPojo.class);

        //校验开关数据
        JSONObject opList = chartOperateEnableDTO.getOpList();
        int opSum = 0;
        for (String opAlisa : opList.keySet()) {
            ChartOperateEnum opEnum = ChartOperateEnum.getByAlias(opAlisa);
            if (Objects.isNull(opEnum)) {
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224011, StatisticsServicesErrorCodeEnum.API_ERROR_224011.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.CHART_OPERATE_ENABLE));
            }

            if(ChartOperateEnum.mutexType(opEnum)){
                if(Objects.equals(EnableEnum.OPEN.getCode(),opList.getInteger(opAlisa))){
                    opSum++;
                }
            }
        }
        //校验互斥关系
        if(opSum >= BasicConstant.TWO){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224096);
        }
        explainsPojo.setOp(opList);
        //explainsPojo转为json存入chart
        explains = JsonHelperUtil.parseObject(JSONObject.toJSONString(explainsPojo));
        entity.setExplains(explains);
        entity.setUpdateTime(DateTimeUtil.getInt());
        if (Objects.equals(statisticsType, StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())) {
            chartModel.update(entity);
        } else {
            chartCustomModel.update(entity);
        }

        // 日志
        String opUserName = chartOperateEnableDTO.getLoginUserName();
        String operationName;
        OperateTypeEnum operateTypeEnum;
        if(EnableEnum.OPEN.getCode().equals(chartOperateEnableDTO.getEnable())){
            operationName = EnableEnum.OPEN.getMemo();
            operateTypeEnum = OperateTypeEnum.ENABLE;
        }else{
            operationName = EnableEnum.CLOSE.getMemo();
            operateTypeEnum = OperateTypeEnum.CLOSE;
        }
        String opMemo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.CHART_LOG_MEMO_OPERATE_ENABLE), opUserName, operationName, entity.getName(), operateEnum.getMemo());
        mongoLogHelp.buildLog(corpid, chartOperateEnableDTO.getUserId(), opUserName, OperateModuleTypeEnum.CHART, operateTypeEnum, chartId.toString(), entity.getName(), opMemo, chartOperateEnableDTO.getHttpHeader());
        return new BaseVO();
    }

    /**
     * 地图和漏斗图将explains里面的部分数据提取到外层回显
     * @param chartEntity
     * @param chartEntityEtx
     */
    private void mapAndFunnelExplains(ChartEntity chartEntity,ChartEntityEtx chartEntityEtx){
        // 地图特殊处理
        if (Objects.equals(ChartTypeEnum.MAP_CUSTOM.getCode(),chartEntity.getChartType())){
            JSONObject mapObject = chartEntity.getMap();
            if (null == mapObject){
                JSONObject explains = chartEntity.getExplains();
                if(explains != null ) {
                    mapObject = JSON.parseObject(JSON.toJSONString(explains.get(StringConstant.MAP)));
                }
            }
            JSONArray range;
            if (null != mapObject && CollectionsUtil.isNotEmpty(range = mapObject.getJSONArray(StringConstant.RANGE))){
                if (null != chartEntityEtx){
                    chartEntityEtx.setMapDistrict(range.getString(range.size()-1));
                    chartEntityEtx.setMap(mapObject);
                }else {
                    chartEntity.setMapDistrict(range.getString(range.size()-1));
                    chartEntity.setMap(mapObject);
                }
            }
        }
        // 漏斗图特殊处理
        if (Objects.equals(ChartTypeEnum.FUNNEL.getCode(),chartEntity.getChartType())){
            JSONObject funnelObject = chartEntity.getFunnel();
            if (null == funnelObject){
                JSONObject explains = chartEntity.getExplains();
                if(explains != null ) {
                    funnelObject = JSON.parseObject(JSON.toJSONString(explains.get(StringConstant.FUNNEL)));
                }
            }
            if (null != funnelObject){
                if (null != chartEntityEtx){
                    chartEntityEtx.setFunnel(funnelObject);
                }else {
                    chartEntity.setFunnel(funnelObject);
                }
            }
        }
    }

    /**
     * 注：该方法只针对自定义图表
     * 图表新建、编辑时处理其层级设置：图表新建、编辑是单个图表，但是图表复制操作是整个仪表盘同时保存
     * @param chartSavePojo
     * @param uuidDrillMap key：chart的uuid，value：该chart的drill集合
     * @param insertList 要插入的图表list
     * @param updateList 要更新的图表list
     * @param updateChartIdIn 更新的图表id集合，通过该集合id查询层级list
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void dealWithDrill(ChartSavePojo chartSavePojo, Map<String, JSONArray> uuidDrillMap, List<ChartEntity> insertList, List<ChartEntity> updateList, List<Long> updateChartIdIn) {
        String corpid = chartSavePojo.getCorpid();
        int statisticsType = StatisticsTypeEnum.CUSTOM_STATISTIC.getCode();
        String userId = chartSavePojo.getUserId();
        //新增图表，则层级肯定也是新增；除此之外，更新图表也可能新增层级
        List<ChartDrillEntity> inserts = new ArrayList<>();
        List<ChartDrillEntity> updates = new ArrayList<>();
        if (CollectionsUtil.isNotEmpty(insertList)) {
            for (ChartEntity entity : insertList) {
                String uuid = entity.getUuid();
                JSONArray drill = uuidDrillMap.get(uuid);
                if (Objects.isNull(drill)) {
                    continue;
                }
                ChartDrillEntity drillEntity = new ChartDrillEntity(corpid, statisticsType, entity.getId(), drill, userId);
                inserts.add(drillEntity);
                //移除insertList内的，剩余都是updateList内的
                uuidDrillMap.remove(uuid);
            }
        }
        if (CollectionsUtil.isNotEmpty(updateChartIdIn)) {
            //获取更新的层级
            List<ChartDrillEntity> updateDrillList = chartDrillModel.findByChartId(corpid, statisticsType, updateChartIdIn);
            //图表id - 层级实体
            Map<Long, ChartDrillEntity> cidDrillMap = updateDrillList.stream().collect(Collectors.toMap(c -> c.getChartId(), Function.identity()));
            for (ChartEntity entity : updateList) {
                Long chartId = entity.getId();
                ChartDrillEntity chartDrillEntity = cidDrillMap.get(chartId);
                String uuid = entity.getUuid();
                JSONArray drill = uuidDrillMap.get(uuid);
                boolean insertFlag = Objects.isNull(chartDrillEntity);
                boolean nullFlag = Objects.isNull(drill);
                if (insertFlag && nullFlag) {
                    //即无层级实体，又无层级配置，则不处理：不用更新，也不用插入
                    continue;
                }
                if (nullFlag) {
                    drill = new JSONArray();
                }
                if (insertFlag) {
                    ChartDrillEntity drillEntity = new ChartDrillEntity(corpid, statisticsType, chartId, drill, userId);
                    inserts.add(drillEntity);
                    uuidDrillMap.remove(uuid);
                } else {
                    chartDrillEntity.setDrill(drill);
                    chartDrillEntity.setUpdateTime(DateTimeUtil.getInt());
                    updates.add(chartDrillEntity);
                }
            }
            if (CollectionsUtil.isNotEmpty(updates)) {
                chartDrillModel.updateBatch(updates, corpid);
            }
        }
        if (CollectionsUtil.isNotEmpty(inserts)) {
            chartDrillModel.insertBatch(inserts);
        }
    }

    /**
     * 自定义图表处理一下图表交互按钮集合（历史数据explains内无图表交互配置，需要处理默认值）
     * @param chartEntity
     * @param chartType
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void dealWithExplains(ChartEntityEtx chartEntity, Integer chartType,LinkageListParamPojo listParamPojo) throws XbbException {
        if (!Objects.equals(chartEntity.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
            //只有自定义图表有图表交互按钮
            return;
        }
        JSONObject op = null;
        JSONObject explains = chartEntity.getExplains();
        if (Objects.nonNull(explains)) {
            op = explains.getJSONObject(ChartCommonConstant.CHART_EXPLAINS_OP);
        } else {
            explains = new JSONObject();
            chartEntity.setExplains(explains);
        }
        op = default4ChartOp(chartEntity,chartType, op);

        //开关配置过滤
        filterUnSetConfig(op,ChartOperateEnum.DRILL,chartEntity.getDrill(),chartType,listParamPojo);
        filterUnSetConfig(op,ChartOperateEnum.LINKAGE,chartEntity.getChartLinkage(),chartType,listParamPojo);

        //联动开关权限过滤
        if(!chartEntity.getLinkageFlag()){
            op.remove(ChartOperateEnum.LINKAGE.getAlias());
        }

        //校验互斥的按钮开关是否同时开启
        checkOpEnableBySameTime(op);
        explains.put(ChartCommonConstant.CHART_EXPLAINS_OP, op);
    }

    /**
     * 校验互斥的按钮开关是否同时开启
     *
     * @param op
     * @author zyy
     * @date 2022/12/12
     * @version v1.0
     */
    private void checkOpEnableBySameTime(JSONObject op) {
        if(Objects.isNull(op)){
            return;
        }
        Map<String,Integer> tmpMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (String opKey : op.keySet()) {
            Integer enable = op.getInteger(opKey);
            if(ChartOperateEnum.mutexTypeByAlisa(opKey) && Objects.equals(enable,EnableEnum.OPEN.getCode())){
                //存在互斥关系，并且为开启状态，计数加1
                tmpMap.put(opKey,enable);
            }
        }
        //互斥关闭存在，则都置为关闭状态
        if(tmpMap.size() >= BasicConstant.TWO){
            tmpMap.keySet().forEach(opKey -> {
                op.put(opKey,EnableEnum.CLOSE.getCode());
            });
        }
    }


    /**
     * 有功能按钮的开关，但功能未配置。则过滤
     *
     * @param op 按钮解释
     * @param chartOperateEnum 按钮枚举
     * @param configData 按钮功能配置数据
     * @param chartType 图表类型
     * @author zyy
     * @date 2022/12/9
     * @version v1.0
     */
    private void filterUnSetConfig(JSONObject op,ChartOperateEnum chartOperateEnum, JSONArray configData, Integer chartType,LinkageListParamPojo listParamPojo) throws XbbException {
        Integer operateFlag = op.getInteger(chartOperateEnum.getAlias());
        //无对应开关直接返回
        if(Objects.isNull(operateFlag)){
            return;
        }
        //配置不为空直接返回（未配置才过滤）
        if(CollectionUtils.isNotEmpty(configData)){
            if(Objects.equals(chartOperateEnum,ChartOperateEnum.LINKAGE)){
                if(linkageHelp.checkLinkageConfigRealTime(listParamPojo)){
                    //校验联动的实时数据，判断配置是否为空
                    return;
                }
            }else{
                return;
            }
        }
        //过滤开关
        if(Objects.equals(chartOperateEnum,ChartOperateEnum.DRILL) && Objects.equals(ChartTypeEnum.MAP_CUSTOM.getCode(), chartType)){
            //钻取特殊情况： 钻取配置为空，图表类型为地图，需要保留钻取开关
            return;
        }
        op.remove(chartOperateEnum.getAlias());
    }

    private void updateOperate(ChartEntityEtx chartEntity,JSONObject op) {
        //先设置进来，后续会进行具体的过滤
        if(CollectionUtils.isNotEmpty(chartEntity.getDrill())){
            op.put(ChartOperateEnum.DRILL.getAlias(),EnableEnum.OPEN.getCode());
        }
        if(CollectionUtils.isNotEmpty(chartEntity.getChartLinkage())){
            op.put(ChartOperateEnum.LINKAGE.getAlias(),EnableEnum.OPEN.getCode());
        }
    }

    /**
     * 设置图表的默认图表交互按钮开启情况（未设置就是关闭）
     * @param chartType
     * @param op
     * @return com.alibaba.fastjson.JSONObject
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private JSONObject default4ChartOp(ChartEntityEtx chartEntity,Integer chartType, JSONObject op) {
        //只对没有图表交互开关的自定义图表设置其默认拥有开关情况
        if (Objects.isNull(op)) {
            op = new JSONObject();
            for (ChartOperateEnum cache : ChartOperateEnum.values()) {
                //该操作包含该图表类型，则允许开启
                if (cache.getDefaultChartTypeList().contains(chartType)) {
                    op.put(cache.getAlias(), EnableEnum.OPEN.getCode());
                }
            }
        }else{
            //已经存在op则需要同步按钮
            updateOperate(chartEntity,op);
        }
        return op;
    }

    /**
     * 联动设置可选/不可选列表
     *
     * @param linkageListDTO
     * @return com.xbongbong.pro.statistic.pojo.vo.LinkageListVO
     * @author zyy
     * @date 2022/11/30
     * @version v1.0
     */
    @Override
    public LinkageListVO linkageList(LinkageListDTO linkageListDTO) throws XbbException {
        LinkageListVO resultVO = new LinkageListVO();
        //校验联动权限
        if(linkageHelp.linkageBaseFilter(linkageListDTO.getLoginUser().getPermSet(), linkageListDTO.getCorpid())){
            return resultVO;
        }

        //获取当前分类下所有的图表
        Map<String, Object> paramMap = BeanUtil.convertBean2Map(linkageListDTO, true);
        List<ChartEntity> chartList = new ArrayList<>();
        chartList.addAll(chartCustomModel.findEntitys(paramMap));
        chartList.addAll(chartModel.findEntitys(paramMap));
        if (CollectionsUtil.isEmpty(chartList)){
            return resultVO;
        }
        //获取当前联动图表
        ChartEntity currentChart = null;
        for (ChartEntity chartEntity : chartList) {
            if(Objects.equals(chartEntity.getId(),linkageListDTO.getId())){
                currentChart = chartEntity;
                break;
            }
        }

        JSONObject overAllPermissions = customHelp.chartOverallPermissions(linkageListDTO);
        Map<Long, List<Long>> subDepIdMap = departmentModel.getSubDepIdMap(linkageListDTO.getCorpid(), false);
        LinkageListParamPojo listParamPojo = new LinkageListParamPojo(new ArrayList<>(chartList),currentChart,overAllPermissions,subDepIdMap,linkageListDTO);
        //获取当前分类下可见的图表
        List<ChartEntity> canSeeChartList = linkageHelp.canSeeChartByLinkage(listParamPojo);
        if(CollectionsUtil.isEmpty(canSeeChartList)){
            return resultVO;
        }

        //设置可被联动图表数组
        List<LinkageListPojo> validChartList = linkageHelp.validChartList(currentChart,canSeeChartList);
        //获取不可被联动图表数组（目前只显示不满足数据源条件的不可选图表，不展示其它条件不满足的，如果想要过滤出去的都展示到不可选数组则将canSeeChartList换成chartList）
        List<LinkageListPojo> invalidChartList = linkageHelp.invalidChartList(canSeeChartList,validChartList);

        //返回数据
        return resultVO.initData(validChartList,invalidChartList);
    }

    /**
     * 联动设置保存/编辑
     *
     * @param linkageSaveDTO
     * @return com.xbongbong.paas.toolbox.wrap.BaseVO
     * @author zyy
     * @date 2022/12/7
     * @version v1.0
     */
    @Override
    public BaseVO linkageSave(LinkageSaveDTO linkageSaveDTO) throws XbbException{
        BaseVO baseVO = new BaseVO();
        //校验联动权限
        if(linkageHelp.linkageBaseFilter(linkageSaveDTO.getLoginUser().getPermSet(), linkageSaveDTO.getCorpid())){
            return baseVO;
        }

        //获取图表
        ChartEntity chartEntity = chartCustomModel.getByKey(linkageSaveDTO.getId(),linkageSaveDTO.getCorpid());
        if(Objects.isNull(chartEntity) || Objects.equals(DelEnum.DELETE.getDel(),chartEntity.getDel())){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012);
        }

        //获取联动设置
        JSONArray validChartList = chartEntity.getChartLinkage();
        if(Objects.isNull(validChartList)){
            //兼容图表第一次设置联动的场景
            validChartList = new JSONArray();
        }
        validChartList.clear();
        validChartList.addAll(linkageSaveDTO.getValidChartList());

        //更新数据
        chartEntity.setChartLinkage(validChartList);
        chartCustomModel.update(chartEntity);

        return baseVO;
    }
}
